OpenLB 1.8.1
Loading...
Searching...
No Matches
blockLatticeSTLreader.hh
Go to the documentation of this file.
1/* This file is part of the OpenLB library
2 *
3 * Copyright (C) 2010-2015 Thomas Henn, Mathias J. Krause, Jonathan Jeppener-Haltenhoff
4 * E-mail contact: info@openlb.net
5 * The most recent release of OpenLB can be downloaded at
6 * <http://www.openlb.net/>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program; if not, write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
28#ifndef BLOCK_LATTICE_STL_READER_HH
29#define BLOCK_LATTICE_STL_READER_HH
30
31
32#include <iostream>
33#include <sstream>
34#include <fstream>
35#include <stdexcept>
36#include "core/singleton.h"
38#include "octree.hh"
40
41
42// All OpenLB code is contained in this namespace.
43namespace olb {
44
45
46
47/*
48 * BlockLatticeSTLreader functions
49 */
50template<typename T>
51BlockLatticeSTLreader<T>::BlockLatticeSTLreader(CuboidDecomposition3D<T>& cbg3d, LoadBalancer<T>& hlb, const std::string fName, T voxelSize, T stlSize,
52 int method, bool verbose, T overlap, T max)
53 : _cuboidDecomposition (cbg3d),
54 _loadBalancer(hlb),
55 _voxelSize(voxelSize),
56 _stlSize(stlSize),
57 _overlap(overlap),
58 _fName(fName),
59 _mesh(fName, stlSize),
60 _verbose(verbose),
61 clout(std::cout, "BlockLatticeSTLreader")
62{
63 this->getName() = "BlockLatticeSTLreader";
64
65 if (_verbose) {
66 clout << "Voxelizing ..." << std::endl;
67 }
68
69 Vector<T,3> extension = _mesh.getMax() - _mesh.getMin();
70 if ( util::nearZero(max) ) {
71 max = util::max(extension[0], util::max(extension[1], extension[2])) + _voxelSize;
72 }
73 int j = 0;
74 for (; _voxelSize * util::pow(2, j) < max; j++)
75 ;
76 Vector<T,3> center;
77 T radius = _voxelSize * util::pow(2, j - 1);
78
80 for (unsigned i = 0; i < 3; i++) {
81 center[i] = (_mesh.getMin()[i] + _mesh.getMax()[i]) / 2. - _voxelSize / 4.;
82 }
83
85 _tree = new Octree<T>(center, radius, &_mesh, j, _overlap);
86
88 for (int i = 0; i < 3; i++) {
89 this->_myMin[i] = center[i] + _voxelSize / 2.;
90 this->_myMax[i] = center[i] - _voxelSize / 2.;
91 }
92 for (int i = 0; i < 3; i++) {
93 while (this->_myMin[i] > _mesh.getMin()[i]) {
94 this->_myMin[i] -= _voxelSize;
95 }
96 while (this->_myMax[i] < _mesh.getMax()[i]) {
97 this->_myMax[i] += _voxelSize;
98 }
99 this->_myMax[i] -= _voxelSize;
100 this->_myMin[i] += _voxelSize;
101 }
102
104 switch (method) {
105 case 1:
106 indicate1();
107 break;
108 case 3:
109 indicate3();
110 break;
111 case 4:
112 indicate2_Xray();
113 break;
114 case 5:
115 indicate2_Yray();
116 break;
117 default:
118 indicate2();
119 break;
120 }
121
122 if (_verbose) {
123 print();
124 }
125
126 clout <<"creating of the lists for signed distance function"<< std::endl;
127 _trianglesInCuboidList.resize(_loadBalancer.size());
128 //_cuboidDecomposition.size();
129 for( int iC=0; iC < _loadBalancer.size();iC++)
130 {
131 //_trainglesInCuboidList.emplace_back();
132 int globC = _loadBalancer.glob(iC);
133 auto& cuboid = _cuboidDecomposition.get(globC);
134 for (STLtriangle<T>& triangle : _mesh.getTriangles())
135 {
136 Vector<T,3> center = triangle.getCenter() ;
137/* <<<<<<< HEAD
138 if (cuboid.intersects(center[0], center[1], center[2], 3))
139======= */
140 //TODO!!! For the signed distance function to work correctly, the overlapp (6) in checkInters must be higher than the real overlapp to capture all neighbouring triangles in the overlap correctly
141 if (cuboid.isInside(center, 6))
142
143 {
144 _trianglesInCuboidList[iC].push_back(triangle);
145
146 }
147 }
148 }
149 // clout << "create neighbouring triangels removed" << std::endl;
151 clout <<'\n' << '\n' << "WARNING! The sensitivity in signed distance function could be insufficient for your case!!!" << '\n' << std::endl;
152
153 if (_verbose) {
154
155 clout << "Voxelizing ... OK" << std::endl;
156 }
157}
158
159template<typename T>
161{
162 T sensitivity = 1.e-30;
163 _neighbouringTriangleInCuboidList.resize(_loadBalancer.size());
164 clout << "createNeighbouringTriangleInCuboidVector called" << std::endl;
165 for(int iC=0; iC < _loadBalancer.size();iC++)
166 {
167 _neighbouringTriangleInCuboidList[iC].resize(_trianglesInCuboidList[iC].size());
168
169
170 //searches for the neighbouring triangles in the cuboid
171 for (int ii=0;ii<_neighbouringTriangleInCuboidList[iC].size(); ii++)
172 {
173 std::vector<STLtriangle<T>> vec;
174
175 for(int jj=ii+1;jj<_trianglesInCuboidList[iC].size();jj++)
176 {
177
178 auto& i = (_trianglesInCuboidList[iC])[ii];
179 auto& j = (_trianglesInCuboidList[iC])[jj];
180 STLtriangle<T> pi = i;
181 //searches if there are common edges or vortex in the triangle pair
182 if(norm(i.point[0]-j.point[0]) < sensitivity || norm(i.point[1]-j.point[1]) < sensitivity || norm(i.point[2]-j.point[2]) < sensitivity ||
183 norm(i.point[0]-j.point[1]) < sensitivity || norm(i.point[1]-j.point[2]) < sensitivity || norm(i.point[2]-j.point[0]) < sensitivity ||
184 norm(i.point[0]-j.point[2]) < sensitivity || norm(i.point[1]-j.point[0]) < sensitivity || norm(i.point[2]-j.point[1]) < sensitivity )
185 {
186 STLtriangle<T> pj= j;
187 (_neighbouringTriangleInCuboidList[iC][ii]).push_back(pj);
188 (_neighbouringTriangleInCuboidList[iC][jj]).push_back(pi);
189 }
190 }
191 }
192 }
193 clout << "createneighbouringTriangleInCuboidVector finished" << std::endl;
194}
195
196/*
197 * BlockLatticeSTLreader functions
198 */
199template<typename T>
200BlockLatticeSTLreader<T>::BlockLatticeSTLreader(const std::vector<std::vector<T>> meshPoints, T voxelSize, T stlSize,
201 int method, bool verbose, T overlap, T max)
202 : _voxelSize(voxelSize),
203 _stlSize(stlSize),
204 _overlap(overlap),
205 _fName("meshPoints.stl"),
206 _mesh(meshPoints, stlSize),
207 _verbose(verbose),
208 clout(std::cout, "BlockLatticeSTLreader")
209{
210 this->getName() = "BlockLatticeSTLreader";
211
212 if (_verbose) {
213 clout << "Voxelizing ..." << std::endl;
214 }
215
216 Vector<T,3> extension = _mesh.getMax() - _mesh.getMin();
217 if ( util::nearZero(max) ) {
218 max = util::max(extension[0], util::max(extension[1], extension[2])) + _voxelSize;
219 }
220 int j = 0;
221 for (; _voxelSize * util::pow(2, j) < max; j++)
222 ;
223 Vector<T,3> center;
224 T radius = _voxelSize * util::pow(2, j - 1);
225
227 for (unsigned i = 0; i < 3; i++) {
228 center[i] = (_mesh.getMin()[i] + _mesh.getMax()[i]) / 2. - _voxelSize / 4.;
229 }
230
232
233 _tree = new Octree<T>(center, radius, &_mesh, j, _overlap);
234
236 for (int i = 0; i < 3; i++) {
237 this->_myMin[i] = center[i] + _voxelSize / 2.;
238 this->_myMax[i] = center[i] - _voxelSize / 2.;
239 }
240 for (int i = 0; i < 3; i++) {
241 while (this->_myMin[i] > _mesh.getMin()[i]) {
242 this->_myMin[i] -= _voxelSize;
243 }
244 while (this->_myMax[i] < _mesh.getMax()[i]) {
245 this->_myMax[i] += _voxelSize;
246 }
247 this->_myMax[i] -= _voxelSize;
248 this->_myMin[i] += _voxelSize;
249 }
250 //automaticly choose the method with minimum extension in its direction
251
252 /*if(extension[0] == std::min_element(extension.begin(), extension.end())){
253 method = 4;
254 }
255 else if(extension[1] == std::min_element(extension.begin(), extension.end())){
256 method = 5;
257 }
258 else if(extension[2] == std::min_element(extension.begin(), extension.end())){
259 method = 0;
260 }
261 */
262
263
264 // Indicate nodes of the tree. (Inside/Outside)
265 switch (method) {
266 case 1:
267 indicate1();
268 break;
269 case 3:
270 indicate3();
271 break;
272 case 4:
273 indicate2_Xray();
274 break;
275 case 5:
276 indicate2_Yray();
277 break;
278 default:
279 indicate2();
280 break;
281 }
282
283 if (_verbose) {
284 print();
285 }
286 if (_verbose) {
287 clout << "Voxelizing ... OK" << std::endl;
288 }
289}
290
291template<typename T>
296
297/*
298 * Old indicate function (slower, more stable)
299 * Define three rays (X-, Y-, Z-direction) for each leaf and count intersections
300 * with STL for each ray. Odd number of intersection means inside (Majority vote).
301 */
302
303template<typename T>
305{
306 std::vector<Octree<T>*> leafs;
307 _tree->getLeafs(leafs);
308 typename std::vector<Octree<T>*>::iterator it = leafs.begin();
309 Vector<T,3> dir, pt, s;
310
311 int intersections = 0;
312 int inside = 0;
313 Octree<T>* node = nullptr;
314 T step = 1. / 1000. * _voxelSize;
315 for (; it != leafs.end(); ++it) {
316 inside = 0;
317
318 pt = (*it)->getCenter();
319 intersections = 0;
320 s = pt; // + step;
321
323 dir[0] = 1;
324 dir[1] = 0;
325 dir[2] = 0;
326 while (s[0] < _mesh.getMax()[0] + std::numeric_limits<T>::epsilon()) {
327 node = _tree->find(s, (*it)->getMaxdepth());
328 intersections += node->testIntersection(pt, dir);
329 node->intersectRayNode(pt, dir, s);
330 s = s + step * dir;
331 }
332 inside += (intersections % 2);
333
335 intersections = 0;
336 s = pt; // + step;
337 dir[0] = 0;
338 dir[1] = 1;
339 dir[2] = 0;
340 while (s[1] < _mesh.getMax()[1] + std::numeric_limits<T>::epsilon()) {
341 node = _tree->find(s, (*it)->getMaxdepth());
342 intersections += node->testIntersection(pt, dir);
343 node->intersectRayNode(pt, dir, s);
344 s = s + step * dir;
345 }
346 inside += (intersections % 2);
347
349 intersections = 0;
350 s = pt; // + step;
351 dir[0] = 0;
352 dir[1] = 0;
353 dir[2] = 1;
354 while (s[2] < _mesh.getMax()[2] + std::numeric_limits<T>::epsilon()) {
355 node = _tree->find(s, (*it)->getMaxdepth());
356 intersections += node->testIntersection(pt, dir);
357 node->intersectRayNode(pt, dir, s);
358 s = s + step * dir;
359 }
360 inside += (intersections % 2);
361 (*it)->setInside(inside > 1);
362 }
363}
364
365/*
366 * New indicate function (faster, less stable)
367 * Define ray in Z-direction for each Voxel in XY-layer. Indicate all nodes on the fly.
368 */
369template<typename T>
370void BlockLatticeSTLreader<T>::indicate2()
371{
372 T rad = _tree->getRadius();
373 Vector<T,3> rayPt = _tree->getCenter() - rad + .5 * _voxelSize;
374 Vector<T,3> pt = rayPt;
375 Vector<T,3> rayDir;
376 rayDir[0] = 0.;
377 rayDir[1] = 0.;
378 rayDir[2] = 1.;
379 //Vector<T,3> maxEdge = _tree->getCenter() + rad;
380
381 T step = 1. / 1000. * _voxelSize;
382
383 Octree<T>* node = nullptr;
384 unsigned short rayInside = 0;
385 Vector<T,3> nodeInters;
386 while (pt[0] < _mesh.getMax()[0] + std::numeric_limits<T>::epsilon()) {
387 node = _tree->find(pt);
388 nodeInters = pt;
389 nodeInters[2] = node->getCenter()[2] - node->getRadius();
390 rayInside = 0;
391 while (pt[1] < _mesh.getMax()[1] + std::numeric_limits<T>::epsilon()) {
392 node = _tree->find(pt);
393 nodeInters = pt;
394 nodeInters[2] = node->getCenter()[2] - node->getRadius();
395 rayInside = 0;
396 while (pt[2] < _mesh.getMax()[2] + std::numeric_limits<T>::epsilon()) {
397 node = _tree->find(pt);
398 node->checkRay(nodeInters, rayDir, rayInside);
399 node->intersectRayNode(pt, rayDir, nodeInters);
400 pt = nodeInters + step * rayDir;
401 }
402 pt[2] = rayPt[2];
403 pt[1] += _voxelSize;
404 }
405 pt[1] = rayPt[1];
406 pt[0] += _voxelSize;
407 }
408}
409
410
411
412/*
413 * New indicate function (faster, less stable)
414 * Define ray in X-direction for each Voxel in YZ-layer. Indicate all nodes on the fly.
415 */
416
417template<typename T>
418void BlockLatticeSTLreader<T>::indicate2_Xray()
419{
420 T rad = _tree->getRadius();
421 Vector<T,3> rayPt = _tree->getCenter() - rad + .5 * _voxelSize;
422 Vector<T,3> pt = rayPt;
423 Vector<T,3> rayDir;
424 rayDir[0] = 1.;
425 rayDir[1] = 0.;
426 rayDir[2] = 0.;
427 //Vector<T,3> maxEdge = _tree->getCenter() + rad;
428
429 T step = 1. / 1000. * _voxelSize;
430
431 Octree<T>* node = nullptr;
432 unsigned short rayInside = 0;
433 Vector<T,3> nodeInters;
434 while (pt[2] < _mesh.getMax()[2] + std::numeric_limits<T>::epsilon()) {
435 node = _tree->find(pt);
436 nodeInters = pt;
437 nodeInters[0] = node->getCenter()[0] - node->getRadius();
438 rayInside = 0;
439 while (pt[1] < _mesh.getMax()[1] + std::numeric_limits<T>::epsilon()) {
440 node = _tree->find(pt);
441 nodeInters = pt;
442 nodeInters[0] = node->getCenter()[0] - node->getRadius();
443 rayInside = 0;
444 while (pt[0] < _mesh.getMax()[0] + std::numeric_limits<T>::epsilon()) {
445 node = _tree->find(pt);
446 node->checkRay(nodeInters, rayDir, rayInside);
447 node->intersectRayNode(pt, rayDir, nodeInters);
448 pt = nodeInters + step * rayDir;
449 }
450 pt[0] = rayPt[0];
451 pt[1] += _voxelSize;
452 }
453 pt[1] = rayPt[1];
454 pt[2] += _voxelSize;
455 }
456}
457
458/*
459 * New indicate function (faster, less stable)
460 * Define ray in Y-direction for each Voxel in XZ-layer. Indicate all nodes on the fly.
461 */
462
463template<typename T>
464void BlockLatticeSTLreader<T>::indicate2_Yray()
465{
466 T rad = _tree->getRadius();
467 Vector<T,3> rayPt = _tree->getCenter() - rad + .5 * _voxelSize;
468 Vector<T,3> pt = rayPt;
469 Vector<T,3> rayDir;
470 rayDir[0] = 0.;
471 rayDir[1] = 1.;
472 rayDir[2] = 0.;
473 //Vector<T,3> maxEdge = _tree->getCenter() + rad;
474
475 T step = 1. / 1000. * _voxelSize;
476
477 Octree<T>* node = nullptr;
478 unsigned short rayInside = 0;
479 Vector<T,3> nodeInters;
480 while (pt[2] < _mesh.getMax()[2] + std::numeric_limits<T>::epsilon()) {
481 node = _tree->find(pt);
482 nodeInters = pt;
483 nodeInters[1] = node->getCenter()[1] - node->getRadius();
484 rayInside = 0;
485 while (pt[0] < _mesh.getMax()[0] + std::numeric_limits<T>::epsilon()) {
486 node = _tree->find(pt);
487 nodeInters = pt;
488 nodeInters[1] = node->getCenter()[1] - node->getRadius();
489 rayInside = 0;
490 while (pt[1] < _mesh.getMax()[1] + std::numeric_limits<T>::epsilon()) {
491 node = _tree->find(pt);
492 node->checkRay(nodeInters, rayDir, rayInside);
493 node->intersectRayNode(pt, rayDir, nodeInters);
494 pt = nodeInters + step * rayDir;
495 }
496 pt[1] = rayPt[1];
497 pt[0] += _voxelSize;
498 }
499 pt[0] = rayPt[0];
500 pt[2] += _voxelSize;
501 }
502}
503
504/*
505 * Double ray approach: two times (X-, Y-, Z-direction) for each leaf.
506 * Could be use to deal with double layer triangles and face intersections.
507 */
508template<typename T>
509void BlockLatticeSTLreader<T>::indicate3()
510{
511 std::vector<Octree<T>*> leafs;
512 _tree->getLeafs(leafs);
513 typename std::vector<Octree<T>*>::iterator it = leafs.begin();
514
515 Vector<T,3> dir, pt, s;
516 Octree<T>* node = nullptr;
517 T step = 1. / 1000. * _voxelSize;
518 int intersections;
519 int sum_intersections;
520
521 for (; it != leafs.end(); ++it) {
522 pt = (*it)->getCenter();
523 intersections = 0;
524 sum_intersections = 0;
525 s = pt; // + step;
526
528 dir[0] = 1;
529 dir[1] = 0;
530 dir[2] = 0;
531 while (s[0] < _mesh.getMax()[0] + std::numeric_limits<T>::epsilon()) {
532 node = _tree->find(s, (*it)->getMaxdepth());
533 intersections = node->testIntersection(pt, dir);
534 node->intersectRayNode(pt, dir, s);
535 s = s + step * dir;
536 if (intersections > 0) {
537 sum_intersections++;
538 break;
539 }
540 }
541
543 intersections = 0;
544 s = pt; // + step;
545 dir[0] = 0;
546 dir[1] = 1;
547 dir[2] = 0;
548 while (s[1] < _mesh.getMax()[1] + std::numeric_limits<T>::epsilon()) {
549 node = _tree->find(s, (*it)->getMaxdepth());
550 intersections = node->testIntersection(pt, dir);
551 node->intersectRayNode(pt, dir, s);
552 s = s + step * dir;
553 if (intersections > 0) {
554 sum_intersections++;
555 break;
556 }
557 }
558
560 intersections = 0;
561 s = pt; // + step;
562 dir[0] = 0;
563 dir[1] = 0;
564 dir[2] = 1;
565 while (s[2] < _mesh.getMax()[2] + std::numeric_limits<T>::epsilon()) {
566 node = _tree->find(s, (*it)->getMaxdepth());
567 intersections = node->testIntersection(pt, dir);
568 node->intersectRayNode(pt, dir, s);
569 s = s + step * dir;
570 if (intersections > 0) {
571 sum_intersections++;
572 break;
573 }
574 }
575
577 intersections = 0;
578 s = pt; // + step;
579 dir[0] = -1;
580 dir[1] = 0;
581 dir[2] = 0;
582 while (s[0] > _mesh.getMin()[0] - std::numeric_limits<T>::epsilon()) {
583 node = _tree->find(s, (*it)->getMaxdepth());
584 intersections = node->testIntersection(pt, dir);
585 node->intersectRayNode(pt, dir, s);
586 s = s + step * dir;
587 if (intersections > 0) {
588 sum_intersections++;
589 break;
590 }
591 }
592
594 intersections = 0;
595 s = pt; // + step;
596 dir[0] = 0;
597 dir[1] = -1;
598 dir[2] = 0;
599 while (s[1] > _mesh.getMin()[1] - std::numeric_limits<T>::epsilon()) {
600 node = _tree->find(s, (*it)->getMaxdepth());
601 intersections = node->testIntersection(pt, dir);
602 node->intersectRayNode(pt, dir, s);
603 s = s + step * dir;
604 if (intersections > 0) {
605 sum_intersections++;
606 break;
607 }
608 }
609
611 intersections = 0;
612 s = pt; // + step;
613 dir[0] = 0;
614 dir[1] = 0;
615 dir[2] = -1;
616 while (s[2] > _mesh.getMin()[2] - std::numeric_limits<T>::epsilon()) {
617 node = _tree->find(s, (*it)->getMaxdepth());
618 intersections = node->testIntersection(pt, dir);
619 node->intersectRayNode(pt, dir, s);
620 s = s + step * dir;
621 if (intersections > 0) {
622 sum_intersections++;
623 break;
624 }
625 }
626 (*it)->setInside(sum_intersections > 5);
627 }
628}
629
630template<typename T>
631bool BlockLatticeSTLreader<T>::operator() (bool output[], const T input[])
632{
633 output[0] = false;
634 T coords = _tree->getRadius();
635 Vector<T,3> c(_tree->getCenter());
636 if (c[0] - coords < input[0] && input[0] < c[0] + coords && c[1] - coords < input[1]
637 && input[1] < c[1] + coords && c[2] - coords < input[2] && input[2] < c[2] + coords) {
638 std::vector<T> tmp(input, input + 3);
639 output[0] = _tree->find(tmp)->getInside();
640 }
641 return true;
642}
643
644template<typename T>
645bool BlockLatticeSTLreader<T>::distance(T& distance, const Vector<T,3>& origin,
646 const Vector<T,3>& direction, int iC)
647{
648 Octree<T>* node = nullptr;
649 Vector<T,3> dir(direction);
650 dir = normalize(dir);
651 Vector<T,3> extends = _mesh.getMax() - _mesh.getMin();
652 Vector<T,3> pt(origin);
653 Vector<T,3> q;
654 Vector<T,3> s;
655 Vector<T,3> center = _mesh.getMin() + 1 / 2. * extends;
656 T step = _voxelSize / 1000., a = 0;
657
658 for (int i = 0; i < 3; i++) {
659 extends[i] /= 2.;
660 }
661
662 if (!(_mesh.getMin()[0] < origin[0] && origin[0] < _mesh.getMax()[0]
663 && _mesh.getMin()[1] < origin[1] && origin[1] < _mesh.getMax()[1]
664 && _mesh.getMin()[2] < origin[2] && origin[2] < _mesh.getMax()[2])) {
665 T t = T(), d = T();
666 bool foundQ = false;
667
668 if (dir[0] > 0) {
669 d = _mesh.getMin()[0];
670 t = (d - origin[0]) / dir[0];
671 pt[0] = origin[0] + (t + step) * dir[0];
672 pt[1] = origin[1] + (t + step) * dir[1];
673 pt[2] = origin[2] + (t + step) * dir[2];
674
675 if (_mesh.getMin()[1] < pt[1] && pt[1] < _mesh.getMax()[1]
676 && _mesh.getMin()[2] < pt[2] && pt[2] < _mesh.getMax()[2]) {
677 foundQ = true;
678 }
679 }
680 else if (dir[0] < 0) {
681 d = _mesh.getMax()[0];
682 t = (d - origin[0]) / dir[0];
683 pt[0] = origin[0] + (t + step) * dir[0];
684 pt[1] = origin[1] + (t + step) * dir[1];
685 pt[2] = origin[2] + (t + step) * dir[2];
686 if (_mesh.getMin()[1] < pt[1] && pt[1] < _mesh.getMax()[1]
687 && _mesh.getMin()[2] < pt[2] && pt[2] < _mesh.getMax()[2]) {
688 foundQ = true;
689 }
690 }
691
692 if (dir[1] > 0 && !foundQ) {
693 d = _mesh.getMin()[1];
694 t = (d - origin[1]) / dir[1];
695 pt[0] = origin[0] + (t + step) * dir[0];
696 pt[1] = origin[1] + (t + step) * dir[1];
697 pt[2] = origin[2] + (t + step) * dir[2];
698 if (_mesh.getMin()[0] < pt[0] && pt[0] < _mesh.getMax()[0]
699 && _mesh.getMin()[2] < pt[2] && pt[2] < _mesh.getMax()[2]) {
700 foundQ = true;
701 }
702 }
703 else if (dir[1] < 0 && !foundQ) {
704 d = _mesh.getMax()[1];
705 t = (d - origin[1]) / dir[1];
706 pt[0] = origin[0] + (t + step) * dir[0];
707 pt[1] = origin[1] + (t + step) * dir[1];
708 pt[2] = origin[2] + (t + step) * dir[2];
709 if (_mesh.getMin()[0] < pt[0] && pt[0] < _mesh.getMax()[0]
710 && _mesh.getMin()[2] < pt[2] && pt[2] < _mesh.getMax()[2]) {
711 foundQ = true;
712 }
713 }
714
715 if (dir[2] > 0 && !foundQ) {
716 d = _mesh.getMin()[2];
717 t = (d - origin[2]) / dir[2];
718 pt[0] = origin[0] + (t + step) * dir[0];
719 pt[1] = origin[1] + (t + step) * dir[1];
720 pt[2] = origin[2] + (t + step) * dir[2];
721 if (_mesh.getMin()[0] < pt[0] && pt[0] < _mesh.getMax()[0]
722 && _mesh.getMin()[1] < pt[1] && pt[1] < _mesh.getMax()[1]) {
723 foundQ = true;
724 }
725 }
726 else if (dir[2] < 0 && !foundQ) {
727 d = _mesh.getMax()[2];
728 t = (d - origin[2]) / dir[2];
729 pt[0] = origin[0] + (t + step) * dir[0];
730 pt[1] = origin[1] + (t + step) * dir[1];
731 pt[2] = origin[2] + (t + step) * dir[2];
732 if (_mesh.getMin()[0] < pt[0] && pt[0] < _mesh.getMax()[0]
733 && _mesh.getMin()[1] < pt[1] && pt[1] < _mesh.getMax()[1]) {
734 foundQ = true;
735 }
736 }
737
738 if (!foundQ) {
739 return false;
740 }
741 }
742
743 while ((util::fabs(pt[0] - center[0]) < extends[0])
744 && (util::fabs(pt[1] - center[1]) < extends[1])
745 && (util::fabs(pt[2] - center[2]) < extends[2])) {
746 node = _tree->find(pt);
747 if (node->closestIntersection(Vector<T,3>(origin), dir, q, a)) {
748 Vector<T,3> vek(q - Vector<T,3>(origin));
749 distance = norm(vek);
750 return true;
751 }
752 else {
753 Octree<T>* tmpNode = _tree->find(pt);
754 tmpNode->intersectRayNode(pt, dir, s);
755 for (int i = 0; i < 3; i++) {
756 pt[i] = s[i] + step * dir[i];
757 }
758 }
759 }
760
761 if (_verbose) {
762 clout << "Returning false" << std::endl;
763 }
764 return false;
765}
766
767template<typename T>
769{
770 // Check if the position is on the corner of a triangle
771 unsigned countTriangles = 0;
772 Vector<T,3> normal(T(0));
773
774 for (const STLtriangle<T>& triangle : _mesh.getTriangles()) {
775 if (triangle.isPointInside(pt)) {
776 ++countTriangles;
777 normal+=triangle.getNormal();
778 }
779 }
780 if (countTriangles > 0) {
781 return normal / countTriangles;
782 }
783
784 // if nothing was found return (0,0,0) to indicate that nothing was found
785 return normal;
786}
787
788template<typename T>
789Vector<T,3> BlockLatticeSTLreader<T>::evalSurfaceNormal(const Vector<T,3>& origin)
790{
791 Vector<T,3> normal(0.);
792 PhysR<T,3> closestPoint;
793 T distance = std::numeric_limits<T>::max();
794 STLtriangle<T> t;
795 for (const STLtriangle<T>& triangle : _mesh.getTriangles()) {
796 PhysR<T,3> const pointOnTriangle = triangle.closestPtPointTriangle(origin);
797 //TODO! There could be a problem with concave surfaces on STL when there is a bigger distance there could be no point on the triangle and function does not work!
798 if (triangle.isPointInside(pointOnTriangle))
799 {
800 PhysR<T,3> const currDistance = pointOnTriangle - origin;
801 T currDistanceNorm = norm(currDistance);
802 if (util::nearZero(currDistanceNorm)) {
803 std::cout << "util near zero" << std::endl;
804 return findNormalOnSurface(origin);
805 }
806 else if (distance > currDistanceNorm) {
807 normal = currDistance;
808 distance = currDistanceNorm;
809 closestPoint = pointOnTriangle;
810 t = triangle;
811 }
812 }
813 }
814
815 if (!util::nearZero(norm(normal))) {
816 normal = normalize(normal);
817 }
818 //FP not sure about, how it should work, without that it simply points to the STL!
819 /* else {
820 return normal;
821 }*/
822/*
823 // Possible change of the sign so that the normal fits to the SDF logic
824 if(distance < _voxelSize) {
825 bool isInsideInnerPoint;
826 this->operator()(&isInsideInnerPoint, (closestPoint-_voxelSize*normal).data());
827 bool isInsideOuterPoint;
828 this->operator()(&isInsideOuterPoint, (closestPoint+_voxelSize*normal).data());
829 normal *= (isInsideInnerPoint && !isInsideOuterPoint ? 1 : -1);
830 }
831 else {
832 bool isInside;
833 this->operator()(&isInside, origin.data());
834 normal *= (isInside ? 1 : -1);
835 }*/
836
837 if(util::dotProduct3D(normal, t.getNormal())> 0)
838 {
839
840 distance =-1.*util::fabs(distance);//inside
841 }
842 else
843 {
844 distance =util::fabs(distance);//inside
845 }
846 return normal;
847}
848/*
849template<typename T>
850T BlockLatticeSTLreader<T>::signedDistance(int iC, const Vector<T,3>& input )
851{
852 T distance = std::numeric_limits<T>::max();
853 auto& triangles = _trianglesInCuboidList[iC];
854 STLtriangle<T> _triangle;
855 Vector<T,3> normal;
856 for (const STLtriangle<T>& triangle : triangles)
857 {
858 PhysR<T,3> pointOnTriangle = triangle.closestPtPointTriangle(input);
859 T distance2 = util::min(distance, norm(pointOnTriangle - input));
860 //TODO! There could be a problem with concave surfaces on STL when there is a bigger distance there could be no point on the triangle and function does not work!
861 if(distance2 < distance && triangle.isPointInside(pointOnTriangle))
862 {
863 distance =distance2;
864 _triangle = triangle;
865 normal = normalize(pointOnTriangle - input);
866 }
867 }
868 if(util::dotProduct3D(normal, _triangle.getNormal())> 0)
869 {
870
871 distance =-1.*util::fabs(distance);
872 }
873 else
874 {
875 distance =util::fabs(distance);
876 }
877 return distance;
878}
879
880template<typename T>
881T BlockLatticeSTLreader<T>::signedDistance(const Vector<T,3>& input)
882{
883 int iC = -1;
884 int globC = _cuboidDecomposition.get_iC(input, 0);
885 if (_loadBalancer.isLocal(globC)) {
886 iC = _loadBalancer.loc(globC);
887 } else {
888 globC = _cuboidDecomposition.get_iC(input, 3);
889 if (_loadBalancer.isLocal(globC)) {
890 iC = _loadBalancer.loc(globC);
891 } else {
892 throw std::runtime_error("Distance origin must be located within local cuboid (overlap)");
893 }
894 }
895 return signedDistance(iC, input);
896}
897*/
898
899
901template<typename T>
903{
904
905 using namespace util;
906 T distance = std::numeric_limits<T>::max();
907 auto& triangles = _trianglesInCuboidList[iC];
908 STLtriangle<T> _triangle;
909 int triangle_index=-1;
910 Vector<T,3> normal;
911
912 for (int i=0;i<triangles.size();i++)
913 {
914 auto& triangle = triangles[i];
915 PhysR<T,3> pointOnTriangle = triangle.closestPtPointTriangle(input);
916 T distance2 = util::min(distance, norm(pointOnTriangle - input));
917 if(distance2 < distance && triangle.isPointInside(pointOnTriangle) )
918 {
919 distance =distance2;
920 _triangle = triangle;
921 triangle_index = i;
922 normal = normalize(pointOnTriangle - input);
923 }
924 }
925 Vector<T,3> distancesToEdges = {}, VortexPoint = {}, EdgePoint1 = {}, EdgePoint2 = {};
926 _triangle.getPointToEdgeDistances ((_triangle.closestPtPointTriangle(input)).data(), distancesToEdges);
927 Vector<T,3> pseudoNormal = normal;//used for edge and vortex point type
928 //different threatment for edge points
929 if(_triangle.isEdgePoint(distancesToEdges, EdgePoint1, EdgePoint2))
930 {
931 for(auto& i: _neighbouringTriangleInCuboidList[iC][triangle_index])
932 {
933 if( (EdgePoint1 == i.point[0] || EdgePoint1 == i.point[1] || EdgePoint1 == i.point[2]) && (EdgePoint2 == i.point[0] || EdgePoint2 == i.point[1] || EdgePoint2 == i.point[2]))
934 {
935 pseudoNormal = normalize(M_PI*_triangle.getNormal() + M_PI*i.getNormal());
936 break;
937 }
938 /* if ( i == (_neighbouringTriangleInCuboidList[iC][triangle_index][_neighbouringTriangleInCuboidList[iC][triangle_index].size()-1]))
939 std::cout << "edge not found" << std::endl <<std::endl << std::endl;*/
940 }
941 //set the sign
942 if(util::dotProduct3D(normal, pseudoNormal)> 0)
943 {
944
945 distance =-1.*util::fabs(distance);
946 }
947 else
948 {
949 distance =util::fabs(distance);
950 }
951 }
952 //different threatment for vortex point
953 else if(_triangle.isVortexPoint(distancesToEdges, VortexPoint))
954 {
955 int triangle_counter = 0;
956 Vector<T,3> vortex1, vortex2, edge1, edge2;
957 T dotP;
958 if(VortexPoint == _triangle.point[0])
959 {
960 vortex1 = _triangle.point[1];
961 vortex2 = _triangle.point[2];
962 }
963 else
964 {
965 if(VortexPoint == _triangle.point[1])
966 {
967 vortex1 = _triangle.point[0];
968 vortex2 = _triangle.point[2];
969 }
970 else
971 {
972 if(VortexPoint == _triangle.point[2])
973 {
974 vortex1 = _triangle.point[0];
975 vortex2 = _triangle.point[1];
976 }
977 }
978 }
979 edge1 = normalize(vortex1 - VortexPoint);
980 edge2 = normalize(vortex2 - VortexPoint);
981 dotP = dotProduct3D(edge1, edge2);
982
983 //some problems with 0 and pi angle in acos
984 if(dotP < -0.999999)
985 pseudoNormal = M_PI*_triangle.getNormal();
986 else if(dotP > 0.999999)
987 {pseudoNormal = 0;}
988 else
989 {
990 pseudoNormal = acos(dotP)*_triangle.getNormal();
991 triangle_counter++;
992 }
993
994 for(auto& i: _neighbouringTriangleInCuboidList[iC][triangle_index])
995 {
996 if( VortexPoint == i.point[0] || VortexPoint == i.point[1] || VortexPoint == i.point[2])
997 {
998 Vector<T,3> vortex1, vortex2, edge1, edge2;
999 T dotP;
1000 if(VortexPoint == i.point[0])
1001 {
1002 vortex1 = i.point[1];
1003 vortex2 = i.point[2];
1004 }
1005 else
1006 {
1007 if(VortexPoint == i.point[1])
1008 {
1009 vortex1 = i.point[0];
1010 vortex2 = i.point[2];
1011 }
1012 else
1013 {
1014 if(VortexPoint == i.point[2])
1015 {
1016 vortex1 = i.point[0];
1017 vortex2 = i.point[1];
1018 }
1019 else
1020 std::cout << "something went wrong" << std::endl;
1021 }
1022 }
1023 edge1 = normalize(vortex1 - VortexPoint);
1024 edge2 = normalize(vortex2 - VortexPoint);
1025 dotP = dotProduct3D(edge1, edge2);
1026 //std::cout << "inside if" << std::endl;
1027 //some problems with 0 and pi angle in acos
1028 if(dotP < -0.999999)
1029 { pseudoNormal += M_PI*i.getNormal();}
1030 else if(dotP > 0.999999)
1031 {;}
1032 else
1033 {
1034 pseudoNormal += acos(dotP)*i.getNormal();
1035 triangle_counter++;
1036 }
1037 }
1038
1039 }
1040 pseudoNormal = normalize(pseudoNormal);
1041 /* std::cout << "normal " << normal << "pseudonormal " << pseudoNormal << std::endl << std::endl;
1042 std::cout << "dotProduct3D is " << util::dotProduct3D(normal, pseudoNormal) << std::endl;
1043 std::cout << "number of triangle " << triangle_counter << std::endl; */
1044
1045 if(util::dotProduct3D(normal, pseudoNormal)> 0)
1046 {
1047
1048 distance =-1.*util::fabs(distance);
1049 }
1050 else
1051 {
1052 distance =util::fabs(distance);
1053 }
1054
1055 }
1056 else
1057 {
1058 if(util::dotProduct3D(normal, _triangle.getNormal())> 0)
1059 {
1060
1061 distance =-1.*util::fabs(distance);
1062 }
1063 else
1064 {
1065 distance =util::fabs(distance);
1066 }
1067 }
1068 return distance;
1069}
1070
1071template<typename T>
1073{
1074 int iC = -1;
1075 auto globC = _cuboidDecomposition.getC(input, 0);
1076 if (_loadBalancer.isLocal(*globC)) {
1077 iC = _loadBalancer.loc(*globC);
1078 } else {
1079 globC = _cuboidDecomposition.getC(input, 3);
1080 if (_loadBalancer.isLocal(*globC)) {
1081 iC = _loadBalancer.loc(*globC);
1082 } else {
1083 throw std::runtime_error("Distance origin must be located within local cuboid (overlap)");
1084 }
1085 }
1086 return signedDistance(iC, input);
1087}
1088
1089
1090template <typename T>
1092{
1093 return evalSurfaceNormal(pos);
1094}
1095
1096template<typename T>
1098{
1099 _mesh.print();
1100 _tree->print();
1101 clout << "voxelSize=" << _voxelSize << "; stlSize=" << _stlSize << std::endl;
1102 clout << "minPhysR(VoxelMesh)=(" << this->_myMin[0] << "," << this->_myMin[1]
1103 << "," << this->_myMin[2] << ")";
1104 clout << "; maxPhysR(VoxelMesh)=(" << this->_myMax[0] << ","
1105 << this->_myMax[1] << "," << this->_myMax[2] << ")" << std::endl;
1106}
1107
1108template<typename T>
1110{
1111 _tree->write(_fName);
1112}
1113
1114template<typename T>
1115void BlockLatticeSTLreader<T>::writeSTL(std::string stlName)
1116{
1117 if (stlName == "") {
1118 _mesh.write(_fName);
1119 }
1120 else {
1121 _mesh.write(stlName);
1122 }
1123}
1124
1125template<typename T>
1127{
1128 unsigned int noTris = _mesh.triangleSize();
1129 Vector<T,3> center;
1130 //Octree<T>* node = nullptr;
1131 for (unsigned int i = 0; i < noTris; i++) {
1132 center = _mesh.getTri(i).getCenter();
1133 if (_tree->find(
1134 center + _mesh.getTri(i).normal * util::sqrt(3.) * _voxelSize)->getInside()) {
1135 // cout << "Wrong direction" << std::endl;
1136 Vector<T,3> pt(_mesh.getTri(i).point[0]);
1137 _mesh.getTri(i).point[0] = _mesh.getTri(i).point[2];
1138 _mesh.getTri(i).point[2] = pt;
1139 _mesh.getTri(i).init();
1140 // _mesh.getTri(i).getNormal()[0] *= -1.;
1141 // _mesh.getTri(i).getNormal()[1] *= -1.;
1142 // _mesh.getTri(i).getNormal()[2] *= -1.;
1143 }
1144 }
1145}
1146
1147template<typename T>
1149{
1150 std::vector<Octree<T>*> leafs;
1151 _tree->getLeafs(leafs);
1152 for (auto it = leafs.begin(); it != leafs.end(); ++it) {
1153 if ((*it)->getBoundaryNode()) {
1154 (*it)->setInside(true);
1155 }
1156 }
1157}
1158
1159} // namespace olb
1160
1161#endif
#define M_PI
Input in STL format – header file.
void writeSTL(std::string stlName="")
Writes STL mesh in Si units.
T signedDistance(int locC, const Vector< T, 3 > &input)
Computes signed distance to closest triangle in direction of the surface normal in local cuboid locC.
void print()
Prints console output.
bool operator()(bool output[], const T input[]) override
Returns whether node is inside or not.
void setBoundaryInsideNodes()
Every octree leaf intersected by the STL will be part of the inside nodes.
BlockLatticeSTLreader(CuboidDecomposition3D< T > &cbg3d, LoadBalancer< T > &hlb, const std::string fName, T voxelSize, T stlSize=1, int method=2, bool verbose=false, T overlap=0., T max=0.)
Constructs a new BlockLatticeSTLreader from a file.
Vector< T, 3 > surfaceNormal(const Vector< T, 3 > &pos, const T meshSize=0) override
Finds and returns normal of the closest surface (triangle)
void createNeighbouringTriangleInCuboidVector()
Needed for the signed Distance function: Creates a list of neighbouring triangles for each triangle.
void setNormalsOutside()
Rearranges normals of triangles to point outside of geometry.
bool distance(T &distance, const Vector< T, 3 > &origin, const Vector< T, 3 > &direction, int iC=-1) override
Computes distance to closest triangle intersection.
std::string & getName()
Definition genericF.hh:51
Vector< S, 3 > _myMax
Vector< S, 3 > _myMin
Base class for all LoadBalancer.
Definition vtiWriter.h:42
bool closestIntersection(const Vector< T, 3 > &pt, const Vector< T, 3 > &direction, Vector< T, 3 > &q, T &a)
Test intersection of ray with all triangles in Octree q contains point of closest intersection to pt ...
Definition octree.hh:669
void intersectRayNode(const Vector< T, 3 > &pt, const Vector< T, 3 > &dir, Vector< T, 3 > &s)
Computes intersection of ray with Octree boundaries.
Definition octree.hh:676
int testIntersection(const Vector< T, 3 > &pt, const Vector< T, 3 > &dir, bool print=false)
Test intersection of ray with all triangles in Octree returns number of intersections.
Definition octree.hh:324
Octree< T > * find(const Vector< T, 3 > &, const int &maxDepth=0)
Find the node containing the first param with remaining maxDepth.
Definition octree.hh:263
const T getRadius() const
Gets radius.
Definition octree.h:124
Plain old scalar vector.
Wrapper functions that simplify the use of MPI.
platform_constant Fraction s[Q]
Definition mrt.h:65
platform_constant Fraction t[Q]
Definition rtlbm.h:45
T triangle(Vector< T, 2 > p, Vector< T, 2 > a, Vector< T, 2 > b, Vector< T, 2 > c) any_platform
Exact signed distance to the surface of two-dimensional triangle.
Definition sdf.h:152
Distribution< T > normal(T mean, T stddev)
bool distance(S &distance, const Vector< S, D > &origin, const Vector< S, D > &direction, S precision, S pitch, F1 isInside, F2 isInsideBoundingBox)
Expr sqrt(Expr x)
Definition expr.cpp:225
Expr min(Expr a, Expr b)
Definition expr.cpp:249
Expr max(Expr a, Expr b)
Definition expr.cpp:245
Expr pow(Expr base, Expr exp)
Definition expr.cpp:235
T dotProduct3D(const Vector< T, 3 > &a, const Vector< T, 3 > &b)
dot product, only valid in 3d
Expr fabs(Expr x)
Definition expr.cpp:230
bool nearZero(T a) any_platform
return true if a is close to zero
Definition util.h:402
Top level namespace for all of OpenLB.
constexpr T max(const ScalarVector< T, D, IMPL > &v)
Definition vector.h:466
Vector< T, D > PhysR
Type for spatial (physical) coordinates.
constexpr T norm(const ScalarVector< T, D, IMPL > &a) any_platform
Euclidean vector norm.
constexpr Vector< T, D > normalize(const ScalarVector< T, D, IMPL > &a, T scale=T{1})
Definition vector.h:284
Octree - adapted from http://www.flipcode.com/archives/Octree_Implementation.shtml.
Definition of singletons: global, publicly available information.
bool getPointToEdgeDistances(const Vector< T, 3 > &input, Vector< T, 3 > &output, T sensitivity=1.e-15)
Returns true if the point is on a edge (smaller than sensitivity) and gives the perpendicular distanc...
Definition stlReader.hh:328
bool isVortexPoint(const Vector< T, 3 > &input, Vector< T, 3 > &P, T sensitivity=1.e-15)
Returns true if is near vortex (smaller than sensitivity) and saves in P the vortex points.
Definition stlReader.hh:371
Vector< T, 3 > & getNormal()
Return write access to normal.
Definition stlReader.h:100
bool isEdgePoint(const Vector< T, 3 > &input, Vector< T, 3 > &P1, Vector< T, 3 > &P2, T sensitivity=1.e-15)
Returns true if is near edge (smaller than sensitivity) and not near vortex and saves in P1 and P2 th...
Definition stlReader.hh:343
Vector< T, 3 > closestPtPointTriangle(const Vector< T, 3 > &pt) const
computes closest Point in a triangle to another point.
Definition stlReader.hh:271
std::vector< Vector< T, 3 > > point
A triangle contains 3 Points.
Definition stlReader.h:67