rsvs3D  0.0.0
Codes for the c++ implementation of the 3D RSVS
meshprocessing.cpp
1 #define _USE_MATH_DEFINES
2 
3 #include "meshprocessing.hpp"
4 
5 #include <cmath>
6 #include <iostream>
7 
8 #include "rsvsutils.hpp"
9 #include "triangulate.hpp"
10 #include "voxel.hpp"
11 #include "warning.hpp"
12 
13 using namespace std;
14 
15 void FlattenBoundaryFaces(mesh &meshin)
16 {
17  /*
18  Flattens non flat border faces of a mesh by triangulating them
19 
20  */
21  mesh meshout;
22  vector<int> subList, vertList;
23  std::array<bool, 3> isFlat;
24  triangulation triangleRSVS;
25  int nSurf;
26  double tol = 1e-9;
27 
28  nSurf = meshin.surfs.size();
29  subList.reserve(nSurf);
30 
31  triangleRSVS.stattri.clear();
32  triangleRSVS.trivert.clear();
33  triangleRSVS.PrepareForUse();
34  // Find Non flat boundary faces (only checks for one coordinate being the
35  // same)
36  for (int i = 0; i < nSurf; ++i)
37  {
38  if (meshin.surfs(i)->isBorder && meshin.surfs(i)->edgeind.size() > 3)
39  {
40  meshin.surfs(i)->OrderedVerts(&meshin, vertList);
41  vertList = meshin.verts.find_list(vertList);
42 
43  isFlat.fill(true);
44  int count = vertList.size();
45  for (int j = 1; j < count; ++j)
46  {
47  for (int k = 0; k < 3; ++k)
48  {
49  isFlat[k] = isFlat[k] &&
50  (fabs(meshin.verts(vertList[j])->coord[k] - meshin.verts(vertList[0])->coord[k]) < tol);
51  }
52  }
53  if (!(isFlat[0] || isFlat[1] || isFlat[2]))
54  {
55  subList.push_back(i);
56  }
57  }
58  }
59  // triangulate the container
60  if (subList.size() > 0)
61  {
62  TriangulateContainer(meshin, triangleRSVS, 1, subList);
63  triangleRSVS.meshDep = &meshin;
64 
65  triangleRSVS.PrepareForUse();
66  triangleRSVS.CalcTriVertPos();
67  triangleRSVS.PrepareForUse();
68  // meshin.displight();
69  auto newSurfs = ConcatenateVectorField(meshin.surfs, &surf::edgeind, subList);
70  // cerr << "Num new surfs " << newSurfs.size()-subList.size()
71  // << " from " << subList.size() << endl;
72  MeshTriangulation(meshout, meshin, triangleRSVS.stattri, triangleRSVS.trivert);
73  meshin = meshout;
74  meshin.PrepareForUse();
75  // meshin.displight();
76  meshin.TightenConnectivity();
77  meshin.OrderEdges();
78  // meshin.displight();
79  }
80 }
81 
82 void TriangulateAllFaces(mesh &meshin)
83 {
84  mesh meshout;
85  vector<int> subList;
86  triangulation triangleRSVS;
87  int nSurf;
88 
89  nSurf = meshin.surfs.size();
90  subList.reserve(nSurf);
91 
92  triangleRSVS.stattri.clear();
93  triangleRSVS.trivert.clear();
94  triangleRSVS.PrepareForUse();
95 
96  TriangulateContainer(meshin, triangleRSVS, 1, {});
97  triangleRSVS.meshDep = &meshin;
98 
99  triangleRSVS.PrepareForUse();
100  triangleRSVS.CalcTriVertPos();
101  triangleRSVS.PrepareForUse();
102  // meshin.displight();
103  auto newSurfs = ConcatenateVectorField(meshin.surfs, &surf::edgeind, subList);
104  // cerr << "Num new surfs " << newSurfs.size()-subList.size()
105  // << " from " << subList.size() << endl;
106  MeshTriangulation(meshout, meshin, triangleRSVS.stattri, triangleRSVS.trivert);
107  meshin = meshout;
108  meshin.PrepareForUse();
109  // meshin.displight();
110  meshin.TightenConnectivity();
111  meshin.OrderEdges();
112  // meshin.displight();
113 }
114 
115 std::vector<int> FindHolesInSnake(const snake &snakein, const HashedVector<int, int> &uncertainVert)
116 {
117  /*
118  Resolves the problem of finding points from which to initiate voids
119  in a snake.
120 
121  Takes in a snake and a vector of indices to which snaxels were considered
122  close. These have to be treated separately as there is some uncertainty
123  about wether they are inside or outside. uncertain Vert is a list of
124  indices where the algorithm is known to be invalid
125  */
126 
127  int ii, cntII, jj, cntJJ, kk, cntKK, ll;
128  auto &vols = snakein.snakeconn.volus;
129  std::vector<bool> vertExplored;
130  std::vector<int> holeInds;
131  int vertAct, holeInd = -1;
132  // const vector<int> &surfEdgeind=currVertList;
133  vertExplored.assign(snakein.isMeshVertIn.size(), false);
134  // Go through the volume objects vertices,
135  // looking for a 'from vertex'
136  // From this vertex check if it is in?
137  // Check if it is in closeVert
138  // -> yes and no, we're done
139  // -> yes and yes, explore this vertices neighbours
140  // -> no, nothing to see here go to next from vertex
141  cntII = snakein.snakeconn.volus.size();
142  holeInds.reserve(cntII);
143  for (ii = 0; ii < cntII; ++ii)
144  {
145  cntJJ = vols(ii)->surfind.size();
146  for (jj = 0; jj < cntJJ; ++jj)
147  {
148  auto surfEdgeind =
149  snakein.snakeconn.edges.find_list(snakein.snakeconn.surfs.isearch(vols(ii)->surfind[jj])->edgeind);
150  cntKK = surfEdgeind.size();
151  for (kk = 0; kk < cntKK; ++kk)
152  {
153  for (ll = 0; ll < 2; ++ll)
154  {
155  vertAct = snakein.snaxs.isearch(snakein.snakeconn.edges(surfEdgeind[kk])->vertind[ll])->fromvert;
156  holeInd = FindVertexHole(vertAct, *(snakein.snakemesh()), snakein.isMeshVertIn, uncertainVert,
157  vertExplored);
158  if (holeInd != -1)
159  {
160  break;
161  }
162  }
163  if (holeInd != -1)
164  {
165  break;
166  }
167  }
168  if (holeInd != -1)
169  {
170  break;
171  }
172  }
173  if (holeInd != -1)
174  {
175  holeInds.push_back(holeInd);
176  }
177  std::cout << std::endl << holeInd << std::endl;
178  }
179  return (holeInds);
180 }
181 
191 void PrepareSnakeForCFD(const snake &snakein, double distanceTol, mesh &meshgeom, std::vector<double> &holeCoords)
192 {
193  /*
194 
195  Coordinates of holes are also returned.
196  */
197  mesh meshtemp;
198  triangulation triRSVS;
199  int nHoles;
200  // int nPtsHole, kk, count;
201 
202  std::vector<int> holeIndices;
203 
204  // tecplotfile tecout;
205 
206  // Cleanup the mesh
207  // tecout.OpenFile("../TESTOUT/rsvs_tetgen_mesh.plt");
208  meshtemp = snakein.snakeconn;
209  // tecout.PrintMesh(meshtemp);
210  // meshtemp.displight();
211 
212  auto groupedVertices = GroupCloseSnaxels(snakein, distanceTol);
213  meshtemp.MergeGroupedVertices(groupedVertices);
214  meshtemp.RemoveSingularConnectors();
215 
216  meshtemp.PrepareForUse();
217  meshtemp.TestConnectivityBiDir(__PRETTY_FUNCTION__);
218  meshtemp.TightenConnectivity();
219  meshtemp.OrderEdges();
220  // tecout.PrintMesh(meshtemp);
221  // meshtemp.displight();
222 
223  // Triangulation preparation
224  triRSVS.stattri.clear();
225  triRSVS.trivert.clear();
226  triRSVS.PrepareForUse();
227  TriangulateMesh(meshtemp, triRSVS);
228 
229  triRSVS.PrepareForUse();
230  triRSVS.CalcTriVertPos();
231  MeshTriangulation(meshgeom, meshtemp, triRSVS.stattri, triRSVS.trivert);
232  meshgeom.PrepareForUse();
233  // meshgeom.displight();
234  meshgeom.TightenConnectivity();
235  meshgeom.OrderEdges();
236 
237  // Find number of holes
238  holeIndices = FindHolesInSnake(snakein, groupedVertices);
239  nHoles = holeIndices.size();
240 
241  holeCoords.assign(nHoles * 3, 0.0);
242  // Assign the holes
243  for (int i = 0; i < nHoles; ++i)
244  {
245  for (int j = 0; j < 3; ++j)
246  {
247  holeCoords[i * 3 + j] = snakein.snakemesh()->verts.isearch(holeIndices[i])->coord[j];
248  }
249  }
250 }
251 
252 HashedVector<int, int> GroupCloseSnaxels(const snake &snakein, double distTol)
253 {
254  /*
255  Merges snaxel which are `distTol` to the end of their carrying edge.
256  */
257  HashedVector<int, int> closeVert;
258  std::vector<int> sameSnaxs, rmvInds;
259  int nSnax;
260 
261  nSnax = snakein.snaxs.size();
262  closeVert.vec.assign(nSnax, -1);
263 
264  // This piece of code is going to be incomplete as it won't test
265  // for multiple snaxels very close on the same edge
266  //
267  // closeVert is a list of vertices close
268  for (int i = 0; i < nSnax; ++i)
269  {
270  if ((snakein.snaxs(i)->d < distTol))
271  {
272  closeVert.vec[i] = snakein.snaxs(i)->fromvert;
273  }
274  else if (((1 - snakein.snaxs(i)->d) < distTol))
275  {
276  closeVert.vec[i] = snakein.snaxs(i)->tovert;
277  }
278  }
279 
280  closeVert.GenerateHash();
281  return closeVert;
282 }
283 
284 void TestVertClose(int vertIndIn, std::vector<bool> &isSnaxDone, const mesh &meshin, double distTol,
285  std::vector<int> &sameEdges)
286 {
287  /*
288  recursive function for finding edges which are short and should be collapsed
289  */
290  int nextvertIndIn;
291  if (!isSnaxDone[vertIndIn])
292  {
293  isSnaxDone[vertIndIn] = true;
294  for (auto eInd : meshin.verts(vertIndIn)->edgeind)
295  {
296  double d = 0.0;
297  for (int i = 0; i < 3; ++i)
298  {
299  d += pow((meshin.verts.isearch(meshin.edges.isearch(eInd)->vertind[0])->coord[i] -
300  meshin.verts.isearch(meshin.edges.isearch(eInd)->vertind[1])->coord[i]),
301  2.0);
302  }
303  if (d < distTol)
304  {
305  sameEdges.push_back(eInd);
306  for (int i = 0; i < 2; ++i)
307  {
308  nextvertIndIn = meshin.verts.find(meshin.edges.isearch(eInd)->vertind[i]);
309  TestVertClose(nextvertIndIn, isSnaxDone, meshin, distTol, sameEdges);
310  }
311  }
312  }
313  }
314 }
315 
316 HashedVector<int, int> GroupCloseVertices(const mesh &meshin, double distTol)
317 {
318  /*
319  Groups vertices which are `distTol` close to each other.
320  */
321  std::vector<bool> isSnaxDone, isEdgeDone;
322  HashedVector<int, int> closeVert;
323  std::vector<int> sameEdges, rmvInds;
324  int nSnax, nEdge, nGroup = 1;
325 
326  distTol = distTol * distTol;
327  nSnax = meshin.verts.size();
328  nEdge = meshin.edges.size();
329  closeVert.vec.assign(nSnax, -1);
330  isSnaxDone.assign(nSnax, false);
331  isEdgeDone.assign(nEdge, false);
332  sameEdges.reserve(10);
333  // This piece of code is going to be incomplete as it won't test
334  // for multiple snaxels very close on the same edge
335  //
336  // closeVert is a list of vertices close
337 
338  for (int i = 0; i < nSnax; ++i)
339  {
340  sameEdges.clear();
341  TestVertClose(i, isSnaxDone, meshin, distTol, sameEdges);
342 
343  if (sameEdges.size() > 0)
344  {
345  for (auto eInd : sameEdges)
346  {
347  closeVert.vec[meshin.verts.find(meshin.edges.isearch(eInd)->vertind[0])] = nGroup;
348  // std::cout << meshin.verts.find(
349  // meshin.edges.isearch(eInd)->vertind[0]
350  // ) << " " << nGroup << "|";
351  closeVert.vec[meshin.verts.find(meshin.edges.isearch(eInd)->vertind[1])] = nGroup;
352  // std::cout << meshin.verts.find(
353  // meshin.edges.isearch(eInd)->vertind[1]
354  // ) << " " << nGroup << "|";
355  }
356  // std::cout << "|";
357  ++nGroup;
358  }
359  }
360  // std::cout << std::endl;
361 
362  // std::cout << nGroup << std::endl;
363  closeVert.GenerateHash();
364  return closeVert;
365 }
366 
367 int FindVertexHole(int vertInd, const mesh &meshin, const std::vector<bool> &vertIn,
368  const HashedVector<int, int> &uncertainVert, std::vector<bool> &vertExplored)
369 {
370  /*
371  Starting from vertInd look for a vertex which is definitely a hole.
372 
373  From this vertex check if it is in?
374  Check if it is in closeVert
375  -> yes and no, we're done
376  -> yes and yes, explore this vertices neighbours
377  -> no, nothing to see here go to next from vertex
378  */
379 
380  std::vector<int> currVertList, nextEdgeList;
381  int returnInd = -1;
382  int ii, cntII, jj, cntJJ, vertPos, vertFound;
383 
384  currVertList.reserve(20);
385  nextEdgeList.reserve(20);
386  currVertList.push_back(vertInd);
387 
388  while (currVertList.size() > 0)
389  {
390  nextEdgeList.clear();
391  cntII = currVertList.size();
392  for (ii = 0; ii < cntII; ++ii)
393  {
394  vertPos = meshin.verts.find(currVertList[ii]);
395  if (!vertExplored[vertPos] && vertIn[vertPos])
396  {
397  vertExplored[vertPos] = true;
398  vertFound = uncertainVert.find(currVertList[ii]);
399  if (vertFound == -1)
400  {
401  // Found our point!
402  returnInd = currVertList[ii];
403  // These operations return out of the function
404  currVertList.clear();
405  break;
406  }
407  else
408  {
409  // Add the edges to a list
410  cntJJ = meshin.verts(vertPos)->edgeind.size();
411  for (jj = 0; jj < cntJJ; ++jj)
412  {
413  nextEdgeList.push_back(meshin.verts(vertPos)->edgeind[jj]);
414  }
415  }
416  }
417  }
418  if (returnInd == -1)
419  {
420  // Assign currVertList
421  currVertList.clear();
422  if (nextEdgeList.size() > 0)
423  {
424  currVertList = ConcatenateVectorField(meshin.edges, &edge::vertind, nextEdgeList);
425  }
426  }
427  }
428 
429  return (returnInd);
430 }
431 
432 double DomInter(double x, double y1, double y2)
433 {
434  /*Interpolation function*/
435  return x * (y2 - y1) + y1;
436 }
437 
438 mesh BuildDomain(const std::array<double, 3> &lowerB, const std::array<double, 3> &upperB, double tolInner)
439 {
440  /*
441  Builds a parralelipipede domain stretching from lowerB to upperB
442 
443  `lowerB` and `upperB` must be vectors of size 3. `tolInner` specifies an
444  offset expanding the box by a set amount.
445  */
446  mesh cube;
447  int count;
448 
449  if (lowerB.size() != 3 || upperB.size() != 3)
450  {
451  std::cerr << "Error in " << __PRETTY_FUNCTION__
452  << " vectors must be"
453  " of size 3"
454  << std::endl;
455  RSVS3D_ERROR_ARGUMENT("Input vectors must be of size 3");
456  }
457 
458  std::array<int, 3> dimGrid = {1, 1, 1};
459  BuildBlockGrid(dimGrid, cube);
460 
461  count = cube.verts.size();
462  for (int i = 0; i < count; ++i)
463  {
464  for (int j = 0; j < 3; ++j)
465  {
466  cube.verts[i].coord[j] =
467  (cube.verts[i].coord[j] * ((upperB[j] + tolInner) - (lowerB[j] - tolInner))) + (lowerB[j] - tolInner);
468  }
469  }
470 
471  return cube;
472 }
473 
512 mesh BuildCutCellDomain(const std::array<double, 3> &outerLowerB, const std::array<double, 3> &outerUpperB,
513  const std::array<double, 3> &innerLowerB, const std::array<double, 3> &innerUpperB, int nSteps,
514  std::vector<int> &vertPerSubDomain)
515 {
516  mesh meshdomain, meshtemp;
517  double x;
518  std::array<std::array<double, 2>, 3> scaleDom;
519 
520  // Special case if asked for 0 subdomains
521  if (nSteps == 0)
522  {
523  meshdomain.Init(0, 0, 0, 0);
524  meshdomain.PrepareForUse();
525  return meshdomain;
526  }
527 
528  // Start from inner bound
529  // Then step up
530  vertPerSubDomain.clear();
531  meshdomain = BuildDomain(innerLowerB, innerUpperB, 0.1);
532  meshdomain.PrepareForUse();
533  meshtemp = meshdomain;
534  meshtemp.PrepareForUse();
535  vertPerSubDomain.push_back(meshtemp.verts.size());
536 
537  for (int i = 1; i < nSteps; ++i)
538  {
539  x = double(i) / double(nSteps - 1);
540  for (int j = 0; j < 3; ++j)
541  {
542  scaleDom[j] = {DomInter(x, innerLowerB[j], outerLowerB[j]), DomInter(x, innerUpperB[j], outerUpperB[j])};
543  }
544 
545  meshtemp.Scale(scaleDom);
546  meshtemp.PrepareForUse();
547  meshdomain.MakeCompatible_inplace(meshtemp);
548  meshdomain.Concatenate(meshtemp);
549  meshdomain.PrepareForUse();
550 
551  vertPerSubDomain.push_back(meshtemp.verts.size());
552  }
553 
554  return meshdomain;
555 }
556 
567 double PseudoSurfaceAngle(const mesh &meshin, const std::array<int, 2> &surfInds)
568 {
569  double surfaceAngle = 0.0;
570  auto getcoord = [&](int indexVert) -> const std::vector<double> { return meshin.verts.isearch(indexVert)->coord; };
571  // if one of the surfaces is not at the boundary of the domain (volu==0)
572  // then return 0 angle;
573  for (auto surfind : surfInds)
574  {
575  if (meshin.surfs.isearch(surfind)->voluind[0] != 0 && meshin.surfs.isearch(surfind)->voluind[1] != 0)
576  {
577  return surfaceAngle;
578  }
579  }
580 
581  std::array<std::array<int, 3>, 2> surfPoints;
582  for (int i = 0; i < 2; ++i)
583  {
584  int nPts = meshhelp::Get3PointsInSurface(meshin, surfInds[i], surfPoints[i]);
585  if (nPts != 3)
586  {
587  return surfaceAngle;
588  }
589  }
590 
591  bool surfOrientSame =
592  (meshin.surfs.isearch(surfInds[0])->voluind[0] == 0 &&
593  (meshin.surfs.isearch(surfInds[0])->voluind[0] == meshin.surfs.isearch(surfInds[1])->voluind[0])) ||
594  (meshin.surfs.isearch(surfInds[0])->voluind[1] == 0 &&
595  (meshin.surfs.isearch(surfInds[0])->voluind[1] == meshin.surfs.isearch(surfInds[1])->voluind[1]));
596 
597  surfaceAngle = PlanesDotProduct(getcoord(surfPoints[0][0]), getcoord(surfPoints[0][1]), getcoord(surfPoints[0][2]),
598  getcoord(surfPoints[1][0]), getcoord(surfPoints[1][1 + surfOrientSame]),
599  getcoord(surfPoints[1][2 - surfOrientSame]), true);
600 
601  return (2.0 - (surfaceAngle + 1.0)) / 2.0;
602 }
612 std::vector<double> CalculateEdgeCurvature(const mesh &meshin)
613 {
614  std::vector<double> edgeCurvatures;
615  int nEdges = meshin.edges.size();
616  edgeCurvatures.assign(nEdges, 0);
617  for (int i = 0; i < nEdges; ++i)
618  {
619  int nSurfsEdge = meshin.edges(i)->surfind.size();
620  for (int j = 0; j < nSurfsEdge; ++j)
621  {
622  for (int k = j + 1; k < nSurfsEdge; ++k)
623  {
624  edgeCurvatures[i] +=
625  PseudoSurfaceAngle(meshin, {meshin.edges(i)->surfind[j], meshin.edges(i)->surfind[k]});
626  }
627  }
628  }
629 
630  return edgeCurvatures;
631 }
632 
641 std::vector<double> CalculateVertexCurvature(const mesh &meshin, int smoothingSteps)
642 {
643  std::vector<double> vertCurvatures, edgeCurvatures;
644  int nVerts = meshin.verts.size();
645  int nEdges = meshin.edges.size();
646  int nSteps = 0;
647  vertCurvatures.assign(nVerts, 0);
648  do
649  {
650  if (nSteps == 0)
651  {
652  edgeCurvatures = CalculateEdgeCurvature(meshin);
653  }
654  else
655  {
656  for (int i = 0; i < nEdges; ++i)
657  {
658  edgeCurvatures[i] = 0.0;
659  for (auto vertInd : meshin.edges(i)->vertind)
660  {
661  edgeCurvatures[i] +=
662  vertCurvatures[meshin.verts.find(vertInd)] / meshin.verts.isearch(vertInd)->edgeind.size();
663  }
664  edgeCurvatures[i] = edgeCurvatures[i] / 2;
665  }
666  }
667  for (int i = 0; i < nVerts; ++i)
668  {
669  for (auto edgeInd : meshin.verts(i)->edgeind)
670  {
671  vertCurvatures[i] += edgeCurvatures[meshin.edges.find(edgeInd)];
672  }
673  if (nSteps > 0)
674  {
675  vertCurvatures[i] = vertCurvatures[i] / 2;
676  }
677  }
678  nSteps++;
679  } while (nSteps < smoothingSteps);
680 
681  return vertCurvatures;
682 }
683 
691 std::vector<double> CalculateVertexMinEdgeLength(const mesh &meshin)
692 {
693  std::vector<double> vertEdgeLength;
694  int nVerts = meshin.verts.size();
695  vertEdgeLength.assign(nVerts, 0);
696 
697  auto edgeLength = CalculateEdgeLengths(meshin);
698 
699  for (int i = 0; i < nVerts; ++i)
700  {
701  vertEdgeLength[i] = INFINITY;
702  for (auto edgeInd : meshin.verts(i)->edgeind)
703  {
704  double testLength = edgeLength[meshin.edges.find(edgeInd)];
705  vertEdgeLength[i] = testLength < vertEdgeLength[i] ? testLength : vertEdgeLength[i];
706  }
707  }
708  return vertEdgeLength;
709 }
710 
718 std::vector<double> CalculateVertexMaxEdgeLength(const mesh &meshin)
719 {
720  std::vector<double> vertEdgeLength;
721  int nVerts = meshin.verts.size();
722  vertEdgeLength.assign(nVerts, 0);
723 
724  auto edgeLength = CalculateEdgeLengths(meshin);
725 
726  for (int i = 0; i < nVerts; ++i)
727  {
728  vertEdgeLength[i] = -INFINITY;
729  for (auto edgeInd : meshin.verts(i)->edgeind)
730  {
731  double testLength = edgeLength[meshin.edges.find(edgeInd)];
732  vertEdgeLength[i] = testLength > vertEdgeLength[i] ? testLength : vertEdgeLength[i];
733  }
734  }
735  return vertEdgeLength;
736 }
737 
745 std::vector<double> CalculateVertexMeanEdgeLength(const mesh &meshin)
746 {
747  std::vector<double> vertEdgeLength;
748  int nVerts = meshin.verts.size();
749 
750  vertEdgeLength.assign(nVerts, 0);
751  auto edgeLength = CalculateEdgeLengths(meshin);
752 
753  for (int i = 0; i < nVerts; ++i)
754  {
755  vertEdgeLength[i] = INFINITY;
756  for (auto edgeInd : meshin.verts(i)->edgeind)
757  {
758  double testLength = edgeLength[meshin.edges.find(edgeInd)];
759  vertEdgeLength[i] += testLength;
760  }
761  vertEdgeLength[i] = vertEdgeLength[i] / meshin.verts(i)->edgeind.size();
762  }
763  return vertEdgeLength;
764 }
765 
773 std::vector<double> CalculateEdgeLengths(const mesh &meshin)
774 {
775  std::vector<double> edgeLength;
776  int nEdges = meshin.edges.size();
777  edgeLength.assign(nEdges, 0);
778 
779  for (int i = 0; i < nEdges; ++i)
780  {
781  edgeLength[i] = meshin.edges(i)->Length(meshin);
782  }
783  return edgeLength;
784 }
785 
794 std::vector<double> CoordInVolume(const mesh &meshin)
795 {
796  std::vector<double> vecPts;
797  int nPtsPerVolu;
798  int nVolu;
799 
800  nVolu = meshin.volus.size();
801  vecPts.assign(nVolu * 3, 0.0);
802 
803  for (int i = 0; i < nVolu; ++i)
804  {
805  nPtsPerVolu = 0;
806  for (auto surfInd : meshin.volus(i)->surfind)
807  {
808  for (auto edgeInd : meshin.surfs.isearch(surfInd)->edgeind)
809  {
810  for (auto vertInd : meshin.edges.isearch(edgeInd)->vertind)
811  {
812  for (int j = 0; j < 3; ++j)
813  {
814  vecPts[i * 3 + j] += meshin.verts.isearch(vertInd)->coord[j];
815  nPtsPerVolu++;
816  }
817  }
818  }
819  }
820  for (int j = 0; j < 3; ++j)
821  {
822  vecPts[i * 3 + j] = vecPts[i * 3 + j] / double(nPtsPerVolu);
823  }
824  }
825 
826  return (vecPts);
827 }
828 
837 std::vector<double> VolumeCentroids(const mesh &meshin)
838 {
839  std::vector<double> vecPts;
840  int nVolu;
841 
842  nVolu = meshin.volus.size();
843  vecPts.assign(nVolu * 3, 0.0);
844 
845  for (int i = 0; i < nVolu; ++i)
846  {
847  auto voluCoord = meshin.volus(i)->PseudoCentroid(meshin);
848  for (int j = 0; j < 3; ++j)
849  {
850  vecPts[i * 3 + j] = voluCoord[j];
851  }
852  }
853 
854  return (vecPts);
855 }
856 
869 std::vector<double> VolumeInternalLayers(const mesh &meshin, int nLayers)
870 {
871  if (nLayers < 0)
872  {
873  RSVS3D_ERROR_ARGUMENT("Unknown number of layers.");
874  }
875 
876  size_t nVolu = meshin.volus.size();
877  std::vector<double> vecPts = VolumeCentroids(meshin);
878  auto multcentre = [&](size_t pos) -> double { return double(pos + 1) / double(nLayers + 1); };
879  auto multvert = [&](size_t pos) -> double { return double(nLayers - pos) / double(nLayers + 1); };
880 
881  vecPts.reserve(nVolu * 3 * (8 * size_t(nLayers) + 1));
882  for (size_t i = 0; i < nVolu; ++i)
883  {
884  auto voluVerts = meshin.verts.find_list(meshin.volus(i)->vertind(meshin));
885 
886  for (auto vertSub : voluVerts)
887  {
888  for (size_t j = 0; j < size_t(nLayers); ++j)
889  {
890  for (size_t k = 0; k < 3; ++k)
891  {
892  vecPts.push_back(vecPts[i * 3 + k] * multcentre(j) + meshin.verts(vertSub)->coord[k] * multvert(j));
893  }
894  }
895  }
896  }
897  return (vecPts);
898 }
899 
908 std::vector<double> SurfaceCentroids(const mesh &meshin)
909 {
910  std::vector<double> vecPts;
911  int nSurf;
912 
913  nSurf = meshin.surfs.size();
914  vecPts.assign(nSurf * 3, 0.0);
915 
916  for (int i = 0; i < nSurf; ++i)
917  {
918  auto surfCoord = meshin.surfs(i)->PseudoCentroid(meshin);
919  for (int j = 0; j < 3; ++j)
920  {
921  vecPts[i * 3 + j] = surfCoord[j];
922  }
923  }
924 
925  return (vecPts);
926 }
927 
940 std::vector<double> SurfaceInternalLayers(const mesh &meshin, int nLayers)
941 {
942  if (nLayers < 0)
943  {
944  RSVS3D_ERROR_ARGUMENT("Unknown number of layers.");
945  }
946 
947  size_t nSurfs = meshin.surfs.size();
948  std::vector<double> vecPts = SurfaceCentroids(meshin);
949  auto multcentre = [&](size_t pos) -> double { return double(pos + 1) / double(nLayers + 1); };
950  auto multvert = [&](size_t pos) -> double { return double(nLayers - pos) / double(nLayers + 1); };
951 
952  vecPts.reserve(nSurfs * 3 * (8 * size_t(nLayers) + 1));
953  for (size_t i = 0; i < nSurfs; ++i)
954  {
955  auto tempEdge = meshin.edges.find_list(meshin.surfs(i)->edgeind);
956  auto surfInd = ConcatenateVectorField(meshin.edges, &edge::vertind, tempEdge);
957  auto surfVerts = meshin.verts.find_list(surfInd);
958 
959  for (auto vertSub : surfVerts)
960  {
961  for (size_t j = 0; j < size_t(nLayers); ++j)
962  {
963  for (size_t k = 0; k < 3; ++k)
964  {
965  vecPts.push_back(vecPts[i * 3 + k] * multcentre(j) + meshin.verts(vertSub)->coord[k] * multvert(j));
966  }
967  }
968  }
969  }
970  return (vecPts);
971 }
972 
973 double CotanLaplacianWeight(const vector<double> &centre, const vector<double> &p_im1, const vector<double> &p_i,
974  const vector<double> &p_ip1, coordvec &temp1, coordvec &temp2)
975 {
976  double w_centrei = 0.0;
977 
978  double angle_im1 = Angle3Points(p_im1, centre, p_i, temp1, temp2);
979  double angle_ip1 = Angle3Points(p_ip1, centre, p_i, temp1, temp2);
980  auto cot = [&](double x) -> double { return tan(M_PI_2 - x); };
981 
982  w_centrei = 0.5 * (cot(angle_im1) + cot(angle_ip1));
983 
984  return w_centrei;
985 }
986 
987 int VertexLaplacianVector(const mesh &meshin, const vert *vertsmooth, coordvec &lapVec, bool isOrdered)
988 {
989  coordvec tempPos;
990  coordvec temp1, temp2;
991  double totalCotan = 0.0;
992 
993  // Make sure that we don't allocate or copy data if the laplacian is already
994  // ordered.
995  std::vector<int> edgeIndModif;
996  const std::vector<int> *edgeIndOutPtr = &(vertsmooth->edgeind);
997  if (!isOrdered)
998  {
999  auto retOrder = vertsmooth->OrderEdges(&meshin, edgeIndModif);
1000  if (!rsvs3d::constants::ordering::__isordered(retOrder))
1001  {
1002  return rsvs3d::constants::__failure;
1003  }
1004  edgeIndOutPtr = &edgeIndModif;
1005  }
1006  // Is a reference to either this->edgeind if isOrdered=true or edgeIndModif
1007  // otherwise.
1008  auto &edgindOrdered = *edgeIndOutPtr;
1009 
1010  lapVec.assign(0.0, 0.0, 0.0);
1011  // Cotangent multiplier cannot be defined (could fall back on uniform)
1012  int nVerts = edgindOrdered.size();
1013  if (nVerts < 3)
1014  {
1015  return rsvs3d::constants::__failure;
1016  }
1017 
1018  // Iterates around each
1019  for (int i = 0; i < nVerts; ++i)
1020  {
1021  int connVert = meshin.VertFromVertEdge(vertsmooth->index, edgindOrdered[i]);
1022  int connVert_m1 = meshin.VertFromVertEdge(vertsmooth->index, edgindOrdered[(i - 1 + nVerts) % nVerts]);
1023  int connVert_p1 = meshin.VertFromVertEdge(vertsmooth->index, edgindOrdered[(i + 1) % nVerts]);
1024  tempPos = meshin.verts.isearch(connVert)->coord;
1025 
1026  double currCotan = CotanLaplacianWeight(vertsmooth->coord, meshin.verts.isearch(connVert_m1)->coord,
1027  meshin.verts.isearch(connVert)->coord,
1028  meshin.verts.isearch(connVert_p1)->coord, temp1, temp2);
1029 
1030  if (!isfinite(currCotan))
1031  {
1032  return rsvs3d::constants::__failure;
1033  }
1034  tempPos.mult(currCotan);
1035  totalCotan += currCotan;
1036  lapVec.add(tempPos.usedata());
1037  }
1038 
1039  lapVec.div(totalCotan);
1040  lapVec.substract(vertsmooth->coord);
1041  if (rsvs3d::utils::IsAproxEqual(lapVec.GetNorm(), 0.0))
1042  {
1043  lapVec.assign(0.0, 0.0, 0.0);
1044  }
1045  return rsvs3d::constants::__success;
1046 }
1047 
1048 coordvec VertexLaplacianVector(const mesh &meshin, int vertIndex)
1049 {
1050  coordvec lapVec;
1051  VertexLaplacianVector(meshin, meshin.verts.isearch(vertIndex), lapVec);
1052  return lapVec;
1053 }
1054 
1070 std::array<double, 2> IntersectLineSphere(const coordvec &lineVec, const coordvec &offset, double sphereRadius)
1071 {
1072  double a, b, c;
1073  a = lineVec.dot(lineVec.usedata());
1074  b = 2 * lineVec.dot(offset.usedata());
1075  c = offset.dot(offset.usedata()) - (sphereRadius * sphereRadius);
1076 
1077  double det = b * b - (4 * a * c);
1078  double inva = 1.0 / (2.0 * a);
1079  if (det < 0.0)
1080  {
1081  return {-INFINITY, INFINITY};
1082  }
1083  if (rsvs3d::utils::IsAproxEqual(det, 0.0))
1084  {
1085  double sol = -b * inva;
1086  return {sol, sol};
1087  }
1088  det = sqrt(det);
1089  return {(-b - det) * inva, (-b + det) * inva};
1090 }
1091 
1092 std::array<double, 2> IntersectLineSphere(const coordvec &lineVec, const vector<double> &linePoint,
1093  const coordvec &sphereCentre, double sphereRadius)
1094 {
1095  static coordvec offset;
1096  offset = linePoint;
1097  offset.substract(sphereCentre.usedata());
1098  return IntersectLineSphere(lineVec, offset, sphereRadius);
1099 }
1100 
1101 std::vector<double> MeshUnitNormals(const mesh &meshin)
1102 {
1103  std::vector<double> coords;
1104  int nVert = meshin.verts.size();
1105  coords.reserve(nVert * 3);
1106  coordvec normal;
1107 
1108  grid::coordlist neighCoord;
1109 
1110  for (int i = 0; i < nVert; ++i)
1111  {
1112  meshin.verts(i)->Normal(&meshin, neighCoord, normal);
1113  normal.Normalize();
1114  for (int j = 0; j < 3; ++j)
1115  {
1116  coords.push_back(normal(j));
1117  }
1118  }
1119  return coords;
1120 }
1121 
1122 std::vector<double> MeshLaplacians(const mesh &meshin)
1123 {
1124  std::vector<double> coords;
1125  int nVert = meshin.verts.size();
1126  coords.reserve(nVert * 3);
1127  coordvec lapVec;
1128 
1129  grid::coordlist neighCoord;
1130 
1131  for (int i = 0; i < nVert; ++i)
1132  {
1133  VertexLaplacianVector(meshin, meshin.verts(i), lapVec);
1134 
1135  for (int j = 0; j < 3; ++j)
1136  {
1137  coords.push_back(lapVec(j));
1138  }
1139  }
1140  return coords;
1141 }
Handles the use and norm of a vector for which the norm and the unit value might be needed.
Definition: mesh.hpp:114
Class for mesh handling.
Definition: mesh.hpp:592
int VertFromVertEdge(int v, int e) const
Returns the vertex in edges.isearch(e)->vertind which does not match v.
Definition: mesh.cpp:5926
Definition: snake.hpp:83
Class for a vertex in a mesh.
Definition: mesh.hpp:448
std::vector< const std::vector< double > * > coordlist
Defines a list of coordinates.
Definition: mesh.hpp:87
double Angle3Points(const std::vector< double > &centre, const std::vector< double > &planeVert2, const std::vector< double > &planeVert3, coordvec &vec1, coordvec &vec2)
Calculates a plane's normal vector.
Definition: mesh.cpp:373
Tools for the mathematical processing of meshes.
std::vector< double > CalculateEdgeCurvature(const mesh &meshin)
Calculates the angles between the surfaces connected at an edge.
std::vector< double > CalculateVertexCurvature(const mesh &meshin, int smoothingSteps)
Calculates the vertex curvature.
std::array< double, 2 > IntersectLineSphere(const coordvec &lineVec, const coordvec &offset, double sphereRadius)
Calculates the parametric position along a line at which it intersects a sphere.
std::vector< double > CalculateEdgeLengths(const mesh &meshin)
Calculates the edge lengths.
std::vector< double > SurfaceCentroids(const mesh &meshin)
Generate a vector of coordinates of points at the surfaces pseudo centroid.
mesh BuildCutCellDomain(const std::array< double, 3 > &outerLowerB, const std::array< double, 3 > &outerUpperB, const std::array< double, 3 > &innerLowerB, const std::array< double, 3 > &innerUpperB, int nSteps, std::vector< int > &vertPerSubDomain)
Builds a series of domains with different edge properties controlling the interpolation of the metric...
std::vector< double > CalculateVertexMinEdgeLength(const mesh &meshin)
Calculates the vertex minimum edge length.
std::vector< double > VolumeInternalLayers(const mesh &meshin, int nLayers)
Returns points on edges between volume pseudo centroid and vertices.
std::vector< double > CalculateVertexMeanEdgeLength(const mesh &meshin)
Calculates the vertex mean edge length.
std::vector< double > SurfaceInternalLayers(const mesh &meshin, int nLayers)
Returns points on edges between surface pseudo centroid and vertices.
std::vector< double > VolumeCentroids(const mesh &meshin)
Generate a vector of coordinates of points at the volume pseudo centroid.
double PseudoSurfaceAngle(const mesh &meshin, const std::array< int, 2 > &surfInds)
Calculates the pseudo surface angle.
std::vector< double > CalculateVertexMaxEdgeLength(const mesh &meshin)
Calculates the vertex maximum edge length.
std::vector< double > CoordInVolume(const mesh &meshin)
Generate a vector of coordinates of points probably inside volumes.
void PrepareSnakeForCFD(const snake &snakein, double distanceTol, mesh &meshgeom, std::vector< double > &holeCoords)
Prepares the snake to be used for CFD, removes duplicate points and triangulates it.
Provides various utility functions for the RSVS operation.
Provides a triangulation for snake and meshes.
Generation of cartesian grids.
Provides the error and warning system used by the RSVS3D project.
#define RSVS3D_ERROR_ARGUMENT(M)
Throw a invalid_argument.
Definition: warning.hpp:148