rsvs3D  0.0.0
Codes for the c++ implementation of the 3D RSVS
mesh.cpp
1 #define _USE_MATH_DEFINES
2 
3 #include "mesh.hpp"
4 
5 #include <cmath>
6 #include <fstream>
7 #include <functional>
8 #include <iostream>
9 #include <limits>
10 #include <sstream>
11 #include <stdexcept>
12 
13 #include "rsvsutils.hpp"
14 #include "warning.hpp"
15 
16 // Class function definitions
17 // Mesh Linking methods
18 using namespace std;
19 namespace rsvsorder = rsvs3d::constants::ordering;
20 namespace rsvslogic = rsvs3d::logicals;
21 // --------------------------------------------------------------------------
22 // Implementatation of coordvec
23 // --------------------------------------------------------------------------
24 double &coordvec::operator[](int a)
25 {
26 // returns a reference to the value and can be used to set a value
27 #ifdef SAFE_ACCESS // adds a check in debug mode
28  if ((unsigned_int(a) >= 3) | (0 > a))
29  {
30  RSVS3D_ERROR_RANGE("Index is out of range");
31  }
32 #endif // SAFE_ACCESS
33  isuptodate = 0;
34  return (elems[a]);
35 }
36 double coordvec::operator()(int a) const
37 {
38 // returns the value (cannot be used to set data)
39 #ifdef SAFE_ACCESS // adds a check in debug mode
40  if ((unsigned_int(a) >= 3) | (0 > a))
41  {
42  RSVS3D_ERROR_RANGE("Index is out of range");
43  }
44 #endif // SAFE_ACCESS
45  return (elems[a]);
46 }
47 
48 void coordvec::swap(vector<double> &vecin)
49 {
50  if (int(vecin.size()) != 3)
51  {
52  RSVS3D_ERROR_NOTHROW("Warning : Coordinate vector is being a "
53  "vector other than 3 long");
54  }
55  this->elems.swap(vecin);
56  this->isuptodate = false;
57 }
58 void coordvec::swap(coordvec &coordin)
59 {
60  this->elems.swap(coordin.elems);
61  {
62  auto temp = this->norm;
63  this->norm = coordin.norm;
64  coordin.norm = temp;
65  }
66  {
67  auto temp = this->isuptodate;
68  this->isuptodate = coordin.isuptodate;
69  coordin.isuptodate = temp;
70  }
71 }
72 
73 void coordvec::flipsign()
74 {
75  for (int ii = 0; ii < 3; ++ii)
76  {
77  this->elems[ii] = -this->elems[ii];
78  }
79 }
80 
81 coordvec coordvec::Unit() const
82 {
83  coordvec unitCoordVec = *this;
84  unitCoordVec.Normalize();
85  return (unitCoordVec);
86 }
87 double coordvec::Normalize()
88 {
89  double oldNorm = this->GetNorm();
90 
91  for (int ii = 0; ii < 3; ++ii)
92  {
93  this->elems[ii] = this->elems[ii] / oldNorm;
94  }
95  this->norm = 1;
96  this->isuptodate = 1;
97  return oldNorm;
98 }
99 double coordvec::Unit(const int a) const
100 {
101 #ifdef SAFE_ACCESS // adds a check in debug mode
102  if ((unsigned_int(a) >= 3) | (0 > a))
103  {
104  RSVS3D_ERROR_RANGE("Index is out of range");
105  }
106 #endif // SAFE_ACCESS
107  if (isuptodate == 0)
108  {
109  cerr << "Warning: NORM of coordvec potentially obsolete " << endl;
110  cerr << " in coordvec::Unit(const int a) const" << endl;
111  cerr << " To avoid this message perform read operations"
112  " on coordvec using the () operator"
113  << endl;
114  }
115  return (elems[a] / norm);
116 }
117 
118 double coordvec::GetNorm()
119 {
120  // TEST_RANGE
121  if (!isuptodate)
122  {
123  this->CalcNorm();
124  }
125  return (norm);
126 }
127 double coordvec::GetNorm() const
128 {
129  // TEST_RANGE
130  if (!isuptodate)
131  {
132  RSVS3D_ERROR_ARGUMENT("coordvec is not ready for norm return");
133  }
134  return (norm);
135 }
136 
137 double coordvec::CalcNorm()
138 {
139  norm = sqrt(pow(elems[0], 2) + pow(elems[1], 2) + pow(elems[2], 2));
140  isuptodate = 1;
141  return (norm);
142 }
143 
144 void coordvec::PrepareForUse()
145 {
146  this->CalcNorm();
147 }
148 
149 void coordvec::assign(double a, double b, double c)
150 {
151  elems[0] = a;
152  elems[1] = b;
153  elems[2] = c;
154  this->CalcNorm();
155 }
156 
157 void coordvec::disp() const
158 {
159  cout << "coordvec [" << elems[0] << "," << elems[1] << "," << elems[2] << "] norm " << norm << " utd " << isuptodate
160  << endl;
161 }
162 
163 // Math implementations
164 
165 void coordvec::max(const vector<double> &vecin)
166 {
167  int n = int(elems.size() <= vecin.size() ? elems.size() : vecin.size());
168  for (int ii = 0; ii < n; ++ii)
169  {
170  elems[ii] = elems[ii] >= vecin[ii] ? elems[ii] : vecin[ii];
171  }
172  this->isuptodate = 0;
173 }
174 void coordvec::min(const vector<double> &vecin)
175 {
176  int n = int(elems.size() <= vecin.size() ? elems.size() : vecin.size());
177  for (int ii = 0; ii < n; ++ii)
178  {
179  elems[ii] = elems[ii] <= vecin[ii] ? elems[ii] : vecin[ii];
180  }
181  this->isuptodate = 0;
182 }
183 
184 void coordvec::add(const vector<double> &vecin)
185 {
186  int n = int(elems.size() <= vecin.size() ? elems.size() : vecin.size());
187  for (int ii = 0; ii < n; ++ii)
188  {
189  elems[ii] = elems[ii] + vecin[ii];
190  }
191  this->isuptodate = 0;
192 }
193 void coordvec::substract(const vector<double> &vecin)
194 {
195  int n = int(elems.size() <= vecin.size() ? elems.size() : vecin.size());
196  for (int ii = 0; ii < n; ++ii)
197  {
198  elems[ii] = elems[ii] - vecin[ii];
199  }
200  this->isuptodate = 0;
201 }
202 void coordvec::substractfrom(const vector<double> &vecin)
203 {
204  int n = int(elems.size() <= vecin.size() ? elems.size() : vecin.size());
205  for (int ii = 0; ii < n; ++ii)
206  {
207  elems[ii] = vecin[ii] - elems[ii];
208  }
209  this->isuptodate = 0;
210 }
211 void coordvec::div(const vector<double> &vecin)
212 {
213  int n = int(elems.size() <= vecin.size() ? elems.size() : vecin.size());
214  for (int ii = 0; ii < n; ++ii)
215  {
216  elems[ii] = elems[ii] / vecin[ii];
217  }
218  this->isuptodate = 0;
219 }
220 void coordvec::mult(const vector<double> &vecin)
221 {
222  int n = int(elems.size() <= vecin.size() ? elems.size() : vecin.size());
223  for (int ii = 0; ii < n; ++ii)
224  {
225  elems[ii] = elems[ii] * vecin[ii];
226  }
227  this->isuptodate = 0;
228 }
229 
230 void coordvec::div(double scalin)
231 {
232  this->mult(1.0 / scalin);
233 }
234 void coordvec::mult(double scalin)
235 {
236  int n = int(elems.size());
237  for (int ii = 0; ii < n; ++ii)
238  {
239  elems[ii] = elems[ii] * scalin;
240  }
241  this->norm = scalin * this->norm;
242 }
243 
244 vector<double> coordvec::cross(const std::vector<double> &vecin) const
245 {
246  vector<double> retVec;
247  retVec.assign(3, 0.0);
248 
249  for (int ii = 3; ii < 6; ii++)
250  {
251  retVec[ii % 3] = elems[(ii + 1) % 3] * vecin[(ii + 2) % 3] - elems[(ii - 1) % 3] * vecin[(ii - 2) % 3];
252  }
253  return (retVec);
254 }
255 
256 double coordvec::dot(const std::vector<double> &vecin) const
257 {
258  double retVec = 0.0;
259 
260  for (int ii = 0; ii < 3; ii++)
261  {
262  retVec += elems[ii] * vecin[ii];
263  }
264  return (retVec);
265 }
266 double coordvec::angle(const coordvec &coordin) const
267 {
268  double angle = acos(this->dot(coordin.usedata()) / (coordin.GetNorm() * this->GetNorm()));
269  if (!isfinite(angle))
270  {
271  if (rsvs3d::sign(coordin(0)) == rsvs3d::sign(this->operator()(0)))
272  {
273  angle = 0.0;
274  }
275  else
276  {
277  angle = M_PI;
278  }
279  }
280  return angle;
281 }
282 
284 // Implementation of point location
286 // Detects which volume (if any a point is in)
287 
296 void DiffPoints(const vector<double> &vert1, const vector<double> &vert2, coordvec &diffVerts)
297 {
298  diffVerts = vert1;
299  diffVerts.substractfrom(vert2);
300  diffVerts.CalcNorm();
301 }
302 
313 void DiffPointsFromCentre(const vector<double> &centre, const vector<double> &vert1, const vector<double> &vert2,
314  coordvec &diffVert1, coordvec &diffVert2)
315 {
316  diffVert1 = centre;
317  diffVert2 = centre;
318  diffVert1.substractfrom(vert1);
319  diffVert2.substractfrom(vert2);
320  diffVert1.CalcNorm();
321  diffVert2.CalcNorm();
322 }
323 
333 void PlaneNormal(const vector<double> &planeVert1, const vector<double> &planeVert2, const vector<double> &planeVert3,
334  coordvec &normal, coordvec &temp1)
335 {
336  DiffPointsFromCentre(planeVert1, planeVert2, planeVert3, normal, temp1);
337  normal = temp1.cross(normal.usedata()); // causes allocation
338 }
339 
352 double PlaneNormalAndAngle(const vector<double> &planeVert1, const vector<double> &planeVert2,
353  const vector<double> &planeVert3, coordvec &normal, coordvec &temp1)
354 {
355  DiffPointsFromCentre(planeVert1, planeVert2, planeVert3, normal, temp1);
356  double angle = temp1.angle(normal);
357  normal = temp1.cross(normal.usedata()); // causes allocation
358  return angle;
359 }
360 
373 double Angle3Points(const vector<double> &centre, const vector<double> &planeVert2, const vector<double> &planeVert3,
374  coordvec &normal, coordvec &temp1)
375 {
376  DiffPointsFromCentre(centre, planeVert2, planeVert3, normal, temp1);
377  double angle = temp1.angle(normal);
378  return angle;
379 }
380 
400 double VertexDistanceToPlane(const vector<double> &planeVert1, const vector<double> &planeVert2,
401  const vector<double> &planeVert3, const vector<double> &testVertex, coordvec &temp1,
402  coordvec &temp2)
403 {
404  double planeDistance = 0.0;
405  if (testVertex.size() != 3)
406  {
407  RSVS3D_ERROR_ARGUMENT("testVertices.size() must be of size 3.");
408  }
409 
410  PlaneNormal(planeVert1, planeVert2, planeVert3, temp2, temp1);
411 
412  planeDistance = temp2.dot(testVertex) - temp2.dot(planeVert1);
413 
414  return planeDistance;
415 }
416 
438 vector<double> VerticesDistanceToPlane(const vector<double> &planeVert1, const vector<double> &planeVert2,
439  const vector<double> &planeVert3, const vector<double> &testVertices,
440  coordvec &temp1, coordvec &temp2)
441 {
442  if (testVertices.size() % 3 != 0)
443  {
444  RSVS3D_ERROR_ARGUMENT("testVertices.size() must be a multiple of 3.");
445  }
446 
447  std::vector<double> planeDistances, testVertex;
448  size_t nPts = testVertices.size() / 3;
449  planeDistances.assign(nPts, 0.0);
450  if (nPts == 0)
451  {
452  return planeDistances;
453  }
454  testVertex.assign(3, 0.0);
455  testVertex.assign(testVertices.begin(), testVertices.begin() + 3);
456  planeDistances[0] = VertexDistanceToPlane(planeVert1, planeVert2, planeVert3, testVertex, temp1, temp2);
457  auto planePosition = temp2.dot(planeVert1);
458  for (size_t i = 1; i < nPts; ++i)
459  {
460  testVertex.assign(testVertices.begin() + 3 * i, testVertices.begin() + 3 * i);
461  planeDistances[i] = temp2.dot(testVertex) - planePosition;
462  }
463 
464  return planeDistances;
465 }
466 
467 double VertexDistanceToPlane(const vector<double> &planeVert1, const vector<double> &planeVert2,
468  const vector<double> &planeVert3, const vector<double> &testVertex)
469 {
470  coordvec temp1, temp2;
471  return VertexDistanceToPlane(planeVert1, planeVert2, planeVert3, testVertex, temp1, temp2);
472 }
473 
474 vector<double> VerticesDistanceToPlane(const vector<double> &planeVert1, const vector<double> &planeVert2,
475  const vector<double> &planeVert3, const vector<double> &testVertices)
476 {
477  coordvec temp1, temp2;
478  return VerticesDistanceToPlane(planeVert1, planeVert2, planeVert3, testVertices, temp1, temp2);
479 }
480 
492 vector<int> mesh::VertexInVolume(const vector<double> testVertices, int sizeVert) const
493 {
494  if (sizeVert < 3)
495  {
496  RSVS3D_ERROR_ARGUMENT("sizeVert must be at least 3.");
497  }
498  if (testVertices.size() % sizeVert != 0)
499  {
500  RSVS3D_ERROR_ARGUMENT("testVertices.size() must be a multiple"
501  " of sizeVert.");
502  }
503 
504  vector<int> vertVolumeIndices;
505  size_t nPts = testVertices.size() / sizeVert;
506  vector<double> tempCoord;
507  vertVolumeIndices.assign(nPts, -1);
508 #ifdef RSVS_DIAGNOSTIC_RESOLVED
509  cout << endl
510  << " Number of volumes explored before final "
511  "candidate out of "
512  << this->volus.size() << endl;
513 #endif
514  // Check orientation (OrientFaces is relative which means it can be
515  // facing in or out)
516  // simply test if the 1st one is 0:
517  tempCoord.assign(testVertices.begin(), testVertices.begin() + 3);
518  bool needFlip = meshhelp::VertexInVolume(*this, tempCoord) == 0;
519  for (size_t i = 0; i < nPts; ++i)
520  {
521  tempCoord.assign(testVertices.begin() + i * sizeVert, testVertices.begin() + (i * sizeVert + 3));
522  vertVolumeIndices[i] = meshhelp::VertexInVolume(*this, tempCoord, needFlip);
523  }
524 #ifdef RSVS_DIAGNOSTIC_RESOLVED
525  cout << endl;
526 #endif
527  return vertVolumeIndices;
528 }
529 
530 double PlanesDotProduct(const vector<double> &planeVert1, const vector<double> &planeVert2,
531  const vector<double> &planeVert3, const vector<double> &planeVert4,
532  const vector<double> &planeVert5, const vector<double> &planeVert6, bool normalize)
533 {
534  coordvec normal1, normal2, temp;
535 
536  PlaneNormal(planeVert1, planeVert2, planeVert3, normal1, temp);
537  PlaneNormal(planeVert4, planeVert5, planeVert6, normal2, temp);
538  if (normalize)
539  {
540  normal1.Normalize();
541  normal2.Normalize();
542  }
543  return normal1.dot(normal2.usedata());
544 }
545 
556 coordvec surf::PseudoCentroid(const mesh &meshin) const
557 {
558  coordvec coord;
559 
560  this->PseudoCentroid(meshin, coord);
561 
562  return coord;
563 }
564 
573 int surf::PseudoCentroid(const mesh &meshin, coordvec &coord) const
574 {
575  int ii, n;
576  coordvec edgeCentre;
577  double edgeLength = 0.0;
578  double surfLength = 0.0;
579  coord.assign(0, 0, 0);
580  n = int(this->edgeind.size());
581  for (ii = 0; ii < n; ++ii)
582  {
583  meshin.edges.isearch(this->edgeind[ii])->GeometricProperties(&meshin, edgeCentre, edgeLength);
584  edgeCentre.mult(edgeLength);
585  coord.add(edgeCentre.usedata());
586  surfLength += edgeLength;
587  }
588  if (rsvs3d::utils::IsAproxEqual(surfLength, 0.0))
589  {
590  if (n > 0)
591  {
592  meshin.edges.isearch(this->edgeind[0])->GeometricProperties(&meshin, coord, edgeLength);
593  }
594  }
595  else
596  {
597  coord.div(surfLength);
598  }
599 
600  return surfLength;
601 }
602 
610 coordvec volu::PseudoCentroid(const mesh &meshin) const
611 {
612  coordvec coordVolu, coordSurf;
613  double surfLength, voluLength;
614  coordVolu.assign(0, 0, 0);
615  surfLength = 0.0;
616  voluLength = 0.0;
617  for (auto surfInd : this->surfind)
618  {
619  surfLength = meshin.surfs.isearch(surfInd)->PseudoCentroid(meshin, coordSurf);
620  coordSurf.mult(surfLength);
621  coordVolu.add(coordSurf.usedata());
622  voluLength += surfLength;
623  }
624  if (rsvs3d::utils::IsAproxEqual(voluLength, 0.0))
625  {
626  int n = this->surfind.size();
627  if (n > 0)
628  {
629  surfLength = meshin.surfs.isearch(this->surfind[0])->PseudoCentroid(meshin, coordVolu);
630  }
631  }
632  else
633  {
634  coordVolu.div(voluLength);
635  }
636 
637  return coordVolu;
638 }
639 
650 double VertexNormal(const std::vector<double> &centre, const grid::coordlist &vecPts, coordvec &normal)
651 {
652  // Calculates a normal for each face
653  // and an angle
654  // Need to make sure it is inward pointing
655  //
656 
657  if (vecPts.size() == 0)
658  {
659  RSVS3D_ERROR_ARGUMENT("Attempted to define a smooth step for an empty"
660  "vector of points.");
661  }
662 
663  coordvec planeCurr, planePrev, temp;
665  double totalNormalAngle = 0.0;
667  double totalTangentAngle = 0.0;
668  double currAngle;
669  int count = vecPts.size();
670  int iStart = 0;
671  bool flagInit = true;
672  normal.assign(0.0, 0.0, 0.0);
673  if (count == 0)
674  {
675  return totalTangentAngle;
676  }
677  // Compute initialisation points
678  while (flagInit && iStart < count)
679  {
680  currAngle = PlaneNormalAndAngle(centre, *vecPts.back(), *vecPts[iStart], planePrev, temp);
681  if (rsvs3d::utils::IsAproxEqual(planePrev.GetNorm(), 0.0) || !isfinite(planePrev.GetNorm()) ||
682  !isfinite(currAngle))
683  {
684  iStart++;
685  }
686  else
687  {
688  flagInit = false;
689  }
690  }
691  if (iStart == count)
692  {
693  std::cerr << std::endl;
694  DisplayVector(centre);
695  for (int i = 0; i < count; ++i)
696  {
697  std::cerr << std::endl;
698  DisplayVector(*vecPts[i]);
699  }
700  RSVS3D_ERROR_LOGIC("Could not compute vertex normal the set of points"
701  " surrounding the centre vertex was degenerate (all the same).");
702  }
703  planePrev.Normalize();
704  for (int i = iStart; i < count; ++i)
705  {
706  currAngle = PlaneNormalAndAngle(centre, *vecPts[i], *vecPts[(i + 1) % count], planeCurr, temp);
707  // If the plane has zero area skip the rest of the loop
708  if (rsvs3d::utils::IsAproxEqual(planeCurr.GetNorm(), 0.0) || !isfinite(planeCurr.GetNorm()) ||
709  !isfinite(currAngle))
710  {
711  planeCurr.assign(1, 1, 1);
712  planeCurr.CalcNorm();
713  continue;
714  }
715  planeCurr.Normalize();
716  totalNormalAngle += currAngle;
717  planeCurr.mult(currAngle);
718  normal.add(planeCurr.usedata());
719  planeCurr.Normalize();
720  totalTangentAngle += planeCurr.angle(planePrev);
721  planePrev.swap(planeCurr);
722  if (!isfinite(totalTangentAngle) || !isfinite(totalNormalAngle))
723  {
724  std::cerr << std::endl;
725  DisplayVector(planePrev.usedata());
726  DisplayVector(planeCurr.usedata());
727  std::cerr << totalTangentAngle << " " << totalNormalAngle << std::endl;
728  DisplayVector(centre);
729  DisplayVector(*vecPts[i]);
730  DisplayVector(*vecPts[(i + 1) % count]);
731  RSVS3D_ERROR_NOTHROW("Angles have gone infinite.");
732  }
733  }
734  normal.div(totalNormalAngle);
735  return totalTangentAngle;
736 }
737 
747 std::tuple<coordvec, double> VertexNormal(const std::vector<double> &centre, const grid::coordlist &vecPts)
748 {
749  std::tuple<coordvec, double> returnTup;
750  get<1>(returnTup) = VertexNormal(centre, vecPts, get<0>(returnTup));
751  return returnTup;
752 }
753 
777 int meshhelp::NormalShouldFlip(const std::vector<int> orderedList, int elm1, int elm2, const std::vector<int> &voluind,
778  bool innerComparison)
779 {
780  RSVS3D_ARGCHECK(voluind.size() == 2, "4th argument voluind must be size 2");
781  RSVS3D_ARGCHECK(voluind[0] ^ voluind[1], "4th argument must have one 0 and "
782  "one non zero element.");
783 
784  auto pairOrder = OrderMatchLists(orderedList, elm1, elm2);
785  int isSameOrder = -pairOrder.first;
786  // compares the list vec1 and vec2 returning
787  // 1 if indices p1 and p2 appear in the same order
788  // -1 if indices p1 and p2 appear in opposite orders
789  int flipMultiplier = 0;
790  if ((voluind[1] == 0) && (isSameOrder == -1))
791  { // case 1 right way if pointing through
792  flipMultiplier = 1;
793  }
794  else if ((voluind[0] == 0) && (isSameOrder == 1))
795  { // case 2 right way
796  flipMultiplier = 1;
797  }
798  else if ((voluind[1] == 0) && (isSameOrder == 1))
799  { // case 3 wrong way
800  flipMultiplier = -1;
801  }
802  else if ((voluind[0] == 0) && (isSameOrder == -1))
803  { // case 4 wrong way
804  flipMultiplier = -1;
805  }
806  if (flipMultiplier == 0)
807  {
808  stringstream strerr;
809  strerr << "Flip multiplier was not set in the cases." << std::endl
810  << " isSameOrder " << isSameOrder << "pairOrder (2)" << pairOrder.second << std::endl;
811  RSVS3D_ERROR_LOGIC(strerr.str().c_str());
812  }
813  if (innerComparison)
814  {
815  flipMultiplier = -flipMultiplier;
816  }
817  return flipMultiplier;
818 }
819 
820 int vert::Normal(const mesh *meshin, grid::coordlist &neighCoord, coordvec &normalVec, bool isOrdered) const
821 {
822  std::vector<int> edgeIndOut;
823  auto retVal = this->SurroundingCoords(meshin, neighCoord, isOrdered, &edgeIndOut);
824 
825  if (retVal != rsvs3d::constants::__success)
826  {
827  normalVec.assign(0.0, 0.0, 0.0);
828  return rsvs3d::constants::__failure;
829  }
830 
831  try
832  {
833  VertexNormal(this->coord, neighCoord, normalVec);
834  }
835  catch (...)
836  {
837  normalVec.assign(0.0, 0.0, 0.0);
838  return rsvs3d::constants::__failure;
839  }
840  normalVec.Normalize();
841  if (edgeIndOut.size() > 2)
842  {
843  int surfInd = meshin->SurfFromEdges(edgeIndOut[0], edgeIndOut[1]);
844  if (rsvslogic::__isfound(surfInd) && meshin->surfs.isearch(surfInd)->IsOrdered())
845  {
846  auto needFlip = meshhelp::NormalShouldFlip(meshin->surfs.isearch(surfInd)->edgeind, edgeIndOut[0],
847  edgeIndOut[1], meshin->surfs.isearch(surfInd)->voluind, true);
848 
849  if (needFlip == -1)
850  {
851  normalVec.flipsign();
852  }
853  }
854  else
855  {
856  RSVS3D_ERROR_NOTHROW("Surface not ordered. Cannot orient normal.");
857  }
858  }
859 
860  return rsvs3d::constants::__success;
861 }
862 
863 coordvec vert::Normal(const mesh *meshin) const
864 {
865  grid::coordlist neighCoord;
866  coordvec normalVec;
867 
868  auto retVal = this->Normal(meshin, neighCoord, normalVec);
869 
870  if (retVal != rsvs3d::constants::__success)
871  {
872  normalVec.assign(0.0, 0.0, 0.0);
873  }
874  return normalVec;
875 }
876 
878 // Implementation of mesh dependence
880 
881 int meshdependence::AddParent(mesh *meshin)
882 {
884 
885  parentmesh.push_back(meshin);
886  parentconn.push_back(temp);
887  return (parentmesh.size());
888 }
889 int meshdependence::AddChild(mesh *meshin)
890 {
892 
893  childmesh.push_back(meshin);
894  return (childmesh.size());
895 }
896 void meshdependence::RemoveChild(mesh *meshin)
897 {
898  for (int i = 0; i < int(childmesh.size()); ++i)
899  {
900  if (meshin == childmesh[i])
901  {
902  childmesh.erase(childmesh.begin() + i);
903  }
904  }
905 }
906 void meshdependence::RemoveParent(mesh *meshin)
907 {
908  for (int i = 0; i < int(parentmesh.size()); ++i)
909  {
910  if (meshin == parentmesh[i])
911  {
912  parentmesh.erase(parentmesh.begin() + i);
913  break;
914  }
915  }
916  nParents = parentmesh.size();
917 }
918 
919 void meshdependence::AddParent(mesh *meshin, vector<int> &parentind)
920 {
921  /*
922  parentind needs to be a list of the parent.volus.index matched to elemind
923  that means that running temp.find(parent.volus.index) will return the
924  subscribts of all the child.volus that are contained in that volu
925 
926  Alternatively running temp(volu.find(volus[a].index)) will return the
927  corresponding parent.volus index.
928  */
930 
931  if (parentind.size() != elemind.size())
932  {
933  RSVS3D_ERROR_ARGUMENT("parent and child index list must be"
934  " the same size.");
935  }
936 
937  temp = parentind;
938  temp.GenerateHash();
939 
940  parentmesh.push_back(meshin);
941  parentconn.push_back(temp);
942  nParents = parentmesh.size();
943 }
944 
945 void mesh::RemoveFromFamily()
946 {
947  int jj;
948 
949  for (jj = 0; jj < int(meshtree.parentmesh.size()); jj++)
950  {
951  meshtree.parentmesh[jj]->meshtree.RemoveChild(this);
952  }
953  for (jj = 0; jj < int(meshtree.childmesh.size()); jj++)
954  {
955  meshtree.childmesh[jj]->meshtree.RemoveParent(this);
956  }
957 }
958 
959 void mesh::AddChild(mesh *meshin)
960 {
961  meshtree.AddChild(meshin);
962  meshin->meshtree.AddParent(this);
963 }
964 void mesh::AddParent(mesh *meshin)
965 {
966  meshtree.AddParent(meshin);
967  meshin->meshtree.AddChild(this);
968 }
969 
970 void mesh::AddChild(mesh *meshin, vector<int> &parentind)
971 {
972  if (!meshDepIsSet)
973  {
974  SetMeshDepElm();
975  }
976  meshtree.AddChild(meshin);
977  meshin->meshtree.AddParent(this, parentind);
978 }
979 void mesh::AddParent(mesh *meshin, vector<int> &parentind)
980 {
981  if (!meshDepIsSet)
982  {
983  SetMeshDepElm();
984  }
985  meshtree.AddParent(meshin, parentind);
986  meshin->meshtree.AddChild(this);
987 }
988 
989 void mesh::SetMeshDepElm()
990 {
991  //
992  int ii;
993  meshtree.elemind.clear();
994  switch (meshDim)
995  {
996  case 0:
997  meshtree.elemind.reserve(verts.size());
998  for (ii = 0; ii < int(verts.size()); ii++)
999  {
1000  meshtree.elemind.push_back(verts(ii)->index);
1001  }
1002  break;
1003  case 1:
1004  meshtree.elemind.reserve(edges.size());
1005  for (ii = 0; ii < int(edges.size()); ii++)
1006  {
1007  meshtree.elemind.push_back(edges(ii)->index);
1008  }
1009  break;
1010  case 2:
1011  meshtree.elemind.reserve(surfs.size());
1012  for (ii = 0; ii < int(surfs.size()); ii++)
1013  {
1014  meshtree.elemind.push_back(surfs(ii)->index);
1015  }
1016  break;
1017  case 3:
1018  meshtree.elemind.reserve(volus.size());
1019  for (ii = 0; ii < int(volus.size()); ii++)
1020  {
1021  meshtree.elemind.push_back(volus(ii)->index);
1022  }
1023  break;
1024  }
1025  meshDepIsSet = true;
1026 }
1027 
1028 void mesh::ReturnParentMap(vector<int> &currind, vector<int> &parentpos, vector<pair<int, int>> &parentcases,
1029  vector<double> &voluVals) const
1030 {
1031  size_t ii, ni, jj, nj, nElm, nParCases;
1032  pair<int, int> tempPair;
1033 
1034  currind.clear();
1035  parentpos.clear();
1036  parentcases.clear();
1037 
1038  nParCases = 0;
1039  ni = meshtree.nParents;
1040  nj = meshtree.elemind.size();
1041  nElm = meshtree.elemind.size();
1042 
1043  currind.reserve(nElm * meshtree.nParents);
1044  parentpos.reserve(nElm * meshtree.nParents);
1045  voluVals.reserve(nElm * meshtree.nParents);
1046  parentcases.reserve(this->CountVoluParent());
1047 
1048  for (ii = 0; ii < ni; ++ii)
1049  {
1050  // Build the list of parent cases
1051  nj = meshtree.parentmesh[ii]->volus.size();
1052  tempPair.first = ii;
1053  for (jj = 0; jj < nj; ++jj)
1054  {
1055  tempPair.second = meshtree.parentmesh[ii]->volus(jj)->index;
1056  parentcases.push_back(tempPair);
1057  voluVals.push_back(meshtree.parentmesh[ii]->volus(jj)->volume * meshtree.parentmesh[ii]->volus(jj)->target);
1058  }
1059  for (jj = 0; jj < nElm; ++jj)
1060  {
1061  currind.push_back(meshtree.elemind[jj]);
1062  parentpos.push_back(meshtree.parentmesh[ii]->volus.find(meshtree.parentconn[ii][jj]) + nParCases);
1063  }
1064  nParCases += nj;
1065  }
1066 }
1067 
1068 void mesh::MapVolu2Parent(const vector<double> &fillIn, const vector<pair<int, int>> &parentcases, double volu::*mp)
1069 {
1070  int ii, ni, sub, sub2;
1071 
1072  ni = parentcases.size();
1073  // cout << endl << "new fills: ";
1074  // DisplayVector(fillIn);
1075  // cout << endl << "replacing: " << ni << " | " ;
1076  for (ii = 0; ii < ni; ii++)
1077  {
1078  sub2 = this->meshtree.parentmesh[parentcases[ii].first]->volus.isHash;
1079  sub = this->meshtree.parentmesh[parentcases[ii].first]->volus.find(parentcases[ii].second);
1080  // cout << "(" << this->meshtree.parentmesh[parentcases[ii].first]
1081  // ->volus[sub].fill << " , ";
1082  this->meshtree.parentmesh[parentcases[ii].first]->volus[sub].*mp = fillIn[ii];
1083 
1084  // cout << this->meshtree.parentmesh[parentcases[ii].first]
1085  // ->volus[sub].fill << ") ";
1086  this->meshtree.parentmesh[parentcases[ii].first]->volus.isHash = sub2;
1087  }
1088  // cout<< endl;
1089 }
1090 void mesh::MapVolu2Self(const vector<double> &fillIn, const vector<int> &elms, double volu::*mp)
1091 {
1092  int ii, ni, sub;
1093 
1094  ni = elms.size();
1095  sub = volus.isHash;
1096  for (ii = 0; ii < ni; ii++)
1097  {
1098  volus[volus.find(elms[ii])].*mp = fillIn[ii];
1099  volus.isHash = sub;
1100  }
1101  // cout<< endl;
1102 }
1103 
1104 void mesh::MaintainLineage()
1105 {
1106  // \TODO Method not implemented yet, features:
1107  // - recognise the modifications needed depending on child and
1108  // parent dimensionality
1109  // - Modify the parentconn vec
1110 }
1111 int mesh::CountParents() const
1112 {
1113  return (meshtree.parentmesh.size());
1114 }
1115 int mesh::SurfInParent(int surfind) const
1116 {
1117  int kk1, kk2;
1118  int jj = -1;
1119  int ii = surfs.find(surfind);
1120  bool isParentSurf = false;
1121  if (ii >= 0)
1122  {
1123  kk1 = volus.find(surfs(ii)->voluind[0]);
1124  kk2 = volus.find(surfs(ii)->voluind[1]);
1125  while (!isParentSurf && jj < meshtree.nParents - 1)
1126  {
1127  ++jj;
1128  if ((kk1 != -1) ^ (kk2 != -1))
1129  {
1130  isParentSurf = true;
1131  }
1132  else if (kk1 != -1)
1133  {
1134  isParentSurf = meshtree.parentconn[jj][kk1] != meshtree.parentconn[jj][kk2];
1135  }
1136  }
1137  }
1138  if (isParentSurf)
1139  {
1140  return (jj);
1141  }
1142  else
1143  {
1144  return (-1);
1145  }
1146 }
1147 
1148 void mesh::SurfInParent(vector<int> &listInParent) const
1149 {
1150  int ii, nSurf = surfs.size();
1151  listInParent.clear();
1152  for (ii = 0; ii < nSurf; ++ii)
1153  {
1154  if (SurfInParent(surfs(ii)->index) >= 0)
1155  {
1156  listInParent.push_back((ii));
1157  }
1158  }
1159 }
1160 
1161 void mesh::SurfValuesofParents(int elmInd, vector<double> &vals, int volType) const
1162 {
1163  /*
1164  Extracts the surfaces in the parents corresponding to element elmInd
1165  volType is a selector for which value to extract
1166  */
1167  double surf::*mp;
1168  mp = NULL;
1169  switch (volType)
1170  {
1171  case 0:
1172  mp = &surf::area;
1173  break;
1174  case 1:
1175  mp = &surf::fill;
1176  break;
1177  case 2:
1178  mp = &surf::target;
1179  break;
1180  case 3:
1181  mp = &surf::error;
1182  break;
1183  }
1184 
1185  this->SurfValuesofParents(elmInd, vals, mp);
1186 }
1187 
1188 void mesh::SurfValuesofParents(int elmInd, vector<double> &vals, double surf::*mp) const
1189 {
1190  /*
1191  Extracts the volumes in the parents corresponding to element elmInd
1192  volType is a selector for which value to extract
1193  */
1194  int sub, ii;
1195  vals.clear();
1196 
1197  sub = surfs.find(elmInd);
1198  for (ii = 0; ii < meshtree.nParents; ++ii)
1199  {
1200  vals.push_back(meshtree.parentmesh[ii]->surfs.isearch(meshtree.parentconn[ii][sub])->*mp);
1201  }
1202 }
1203 
1204 void mesh::VoluValuesofParents(int elmInd, vector<double> &vals, int volType) const
1205 {
1206  /*
1207  Extracts the volumes in the parents corresponding to element elmInd
1208  volType is a selector for which value to extract
1209  */
1210 
1211  double volu::*mp;
1212  mp = NULL;
1213  switch (volType)
1214  {
1215  case 0:
1216  mp = &volu::volume;
1217  break;
1218  case 1:
1219  mp = &volu::fill;
1220  break;
1221  case 2:
1222  mp = &volu::target;
1223  break;
1224  case 3:
1225  mp = &volu::error;
1226  break;
1227  }
1228 
1229  this->VoluValuesofParents(elmInd, vals, mp);
1230 }
1231 
1232 void mesh::VoluValuesofParents(int elmInd, vector<double> &vals, double volu::*mp) const
1233 {
1234  /*
1235  Extracts the volumes in the parents corresponding to element elmInd
1236  volType is a selector for which value to extract
1237  */
1238  int sub, ii;
1239  vals.clear();
1240 
1241  sub = volus.find(elmInd);
1242  for (ii = 0; ii < meshtree.nParents; ++ii)
1243  {
1244  vals.push_back(meshtree.parentmesh[ii]->volus.isearch(meshtree.parentconn[ii][sub])->*mp);
1245  }
1246 }
1247 
1248 void mesh::ElmOnParentBound(vector<int> &listInParent, vector<int> &voluInd, bool isBorderBound, bool outerVolume) const
1249 {
1250  if (this->WhatDim() == 3)
1251  {
1252  this->SurfOnParentBound(listInParent, voluInd, isBorderBound, outerVolume);
1253  }
1254  else if (this->WhatDim() == 2)
1255  {
1256  this->EdgeOnParentBound(listInParent, voluInd, isBorderBound, outerVolume);
1257  }
1258 }
1259 
1260 void mesh::SurfOnParentBound(vector<int> &listInParent, vector<int> &voluInd, bool isBorderBound,
1261  bool outerVolume) const
1262 {
1263  /*
1264  Returns a list of surfaces which are on the outer or inner boundaries.
1265  */
1266  int ii, jj, boundVolume, nSurf = surfs.size();
1267  bool isOnBound;
1268  vector<double> vals0, vals1;
1269  listInParent.clear();
1270 
1271  if (outerVolume)
1272  {
1273  boundVolume = 0.0;
1274  }
1275  else
1276  {
1277  boundVolume = 1.0;
1278  } // Mesh component comparison
1279 
1280  vals0.reserve(meshtree.nParents);
1281  vals1.reserve(meshtree.nParents);
1282  voluInd.clear();
1283  voluInd.reserve(volus.size());
1284 
1285  for (ii = 0; ii < nSurf; ++ii)
1286  {
1287  isOnBound = false;
1288  if (surfs(ii)->voluind[0] == 0 || surfs(ii)->voluind[1] == 0)
1289  {
1290  isOnBound = isBorderBound;
1291  if (isOnBound && (surfs(ii)->voluind[0] != 0))
1292  {
1293  voluInd.push_back(surfs(ii)->voluind[0]);
1294  }
1295  if (isOnBound && (surfs(ii)->voluind[1] != 0))
1296  {
1297  voluInd.push_back(surfs(ii)->voluind[1]);
1298  }
1299  }
1300  else if (SurfInParent(surfs(ii)->index) >= 0)
1301  {
1302  // Check parent volume values
1303  this->VoluValuesofParents(surfs(ii)->voluind[0], vals0, &volu::target);
1304  this->VoluValuesofParents(surfs(ii)->voluind[1], vals1, &volu::target);
1305  jj = 0;
1306  // DisplayVector(vals0);
1307  // DisplayVector(vals1);
1308  while (!isOnBound && jj < meshtree.nParents)
1309  {
1310  // To be on bound the left and right values must
1311  // be different and one must be equal to the target
1312  // boundary Value
1313  isOnBound = (fabs(vals0[jj] - boundVolume) < __DBL_EPSILON__) ^
1314  (fabs(vals1[jj] - boundVolume) < __DBL_EPSILON__);
1315  ++jj;
1316  }
1317 
1318  if (isOnBound)
1319  {
1320  if ((fabs(vals1[jj - 1] - boundVolume) < __DBL_EPSILON__))
1321  {
1322  voluInd.push_back(surfs(ii)->voluind[1]);
1323  }
1324  else if ((fabs(vals0[jj - 1] - boundVolume) < __DBL_EPSILON__))
1325  {
1326  voluInd.push_back(surfs(ii)->voluind[0]);
1327  }
1328  }
1329 
1330  // cout << "? " << isOnBound << " || ";
1331  }
1332  if (isOnBound)
1333  {
1334  listInParent.push_back(surfs(ii)->index);
1335  }
1336  }
1337 }
1338 
1339 void mesh::EdgeOnParentBound(vector<int> &listInParent, vector<int> &surfInd, bool isBorderBound,
1340  bool outerVolume) const
1341 {
1342  /*
1343  Returns a list of edges which are on the outer or inner boundaries.
1344  */
1345  int ii, jj, boundVolume, nSurf = edges.size();
1346  bool isOnBound;
1347  vector<double> vals0, vals1;
1348  listInParent.clear();
1349 
1350  if (outerVolume)
1351  {
1352  boundVolume = 0.0;
1353  }
1354  else
1355  {
1356  boundVolume = 1.0;
1357  } // Mesh component comparison
1358 
1359  vals0.reserve(meshtree.nParents);
1360  vals1.reserve(meshtree.nParents);
1361  surfInd.clear();
1362  surfInd.reserve(surfs.size());
1363 
1364  for (ii = 0; ii < nSurf; ++ii)
1365  {
1366  isOnBound = false;
1367  if (edges(ii)->surfind[0] == 0 || edges(ii)->surfind[1] == 0)
1368  {
1369  isOnBound = isBorderBound;
1370  if (isOnBound && (edges(ii)->surfind[0] != 0))
1371  {
1372  surfInd.push_back(edges(ii)->surfind[0]);
1373  }
1374  if (isOnBound && (edges(ii)->surfind[1] != 0))
1375  {
1376  surfInd.push_back(edges(ii)->surfind[1]);
1377  }
1378  }
1379  else if (SurfInParent(edges(ii)->index) >= 0)
1380  {
1381  // Check parent surfme values
1382  this->SurfValuesofParents(edges(ii)->surfind[0], vals0, &surf::target);
1383  this->SurfValuesofParents(edges(ii)->surfind[1], vals1, &surf::target);
1384  jj = 0;
1385  // DisplayVector(vals0);
1386  // DisplayVector(vals1);
1387  while (!isOnBound && jj < meshtree.nParents)
1388  {
1389  isOnBound = (vals0[jj] != vals1[jj]) && ((vals0[jj] == boundVolume) || (vals1[jj] == boundVolume));
1390  ++jj;
1391  }
1392 
1393  if (isOnBound && (vals1[jj - 1] == boundVolume))
1394  {
1395  surfInd.push_back(edges(ii)->surfind[1]);
1396  if (boundVolume == 1.0 && surfs.isearch(surfInd.back())->isBorder)
1397  {
1398  surfInd.pop_back();
1399  }
1400  }
1401  if (isOnBound && (vals0[jj - 1] == boundVolume))
1402  {
1403  surfInd.push_back(edges(ii)->surfind[0]);
1404  if (boundVolume == 1.0 && surfs.isearch(surfInd.back())->isBorder)
1405  {
1406  surfInd.pop_back();
1407  }
1408  }
1409 
1410  // cout << "? " << isOnBound << " || ";
1411  }
1412  if (isOnBound)
1413  {
1414  listInParent.push_back(edges(ii)->index);
1415  }
1416  }
1417 }
1418 
1419 int mesh::CountVoluParent() const
1420 {
1421  int n = 0;
1422  for (int i = 0; i < int(meshtree.parentmesh.size()); ++i)
1423  {
1424  n += meshtree.parentmesh[i]->volus.size();
1425  }
1426  return (n);
1427 }
1428 
1429 int mesh::ParentElementIndex(int childElmInd, int parentInd) const
1430 {
1431  /*
1432  Returns the parent of an element.
1433  */
1434  if (parentInd >= int(this->meshtree.parentconn.size()) || parentInd < 0)
1435  {
1436  RSVS3D_ERROR_ARGUMENT("parentInd is larger than the number"
1437  " of mesh parents");
1438  }
1439  if (this->WhatDim() == 3)
1440  {
1441  return (this->meshtree.parentconn[parentInd][this->volus.find(childElmInd)]);
1442  }
1443  else if (this->WhatDim() == 2)
1444  {
1445  return (this->meshtree.parentconn[parentInd][this->surfs.find(childElmInd)]);
1446  }
1447  else
1448  {
1449  RSVS3D_ERROR_ARGUMENT("Dimensionality other than 2 or"
1450  " 3 not supported yet");
1451  return (-1);
1452  }
1453 }
1454 
1456 void edge::GeometricProperties(const mesh *meshin, coordvec &centre, double &length) const
1457 {
1458  int sub;
1459  centre.assign(0, 0, 0);
1460  length = 0.0;
1461  sub = meshin->verts.find(vertind[0]);
1462  centre.substract(meshin->verts(sub)->coord);
1463  centre.add(meshin->verts.isearch(vertind[1])->coord);
1464  length = centre.CalcNorm();
1465  centre.add(meshin->verts(sub)->coord);
1466  centre.add(meshin->verts(sub)->coord);
1467  centre.div(2.0);
1468 }
1469 
1477 double edge::LengthSquared(const mesh &meshin) const
1478 {
1479  double lengthSquared = 0.0;
1480 
1481  for (int i = 0; i < meshin.WhatDim(); ++i)
1482  {
1483  lengthSquared += pow(
1484  meshin.verts.isearch(this->vertind[0])->coord[i] - meshin.verts.isearch(this->vertind[1])->coord[i], 2.0);
1485  }
1486 
1487  return lengthSquared;
1488 }
1496 double edge::Length(const mesh &meshin) const
1497 {
1498  if (rsvs3d::constants::__issetlength(this->length))
1499  {
1500  return this->length;
1501  }
1502  return sqrt(this->LengthSquared(meshin));
1503 }
1514 bool edge::IsLength0(const mesh &meshin, double eps) const
1515 {
1516  if (rsvs3d::constants::__issetlength(this->length))
1517  {
1518  return fabs(this->length) < fabs(eps);
1519  }
1520  return this->LengthSquared(meshin) < pow(eps, 2.0);
1521 }
1522 
1523 // Methods of meshpart : volu surf edge vert
1524 void volu::disp() const
1525 {
1526  int i;
1527  cout << "volu : index " << index << " | fill " << fill << ", " << target << ", " << error << " | isBorder "
1528  << isBorder << " | surfind " << surfind.size() << ":";
1529  if (surfind.size() < 30)
1530  {
1531  for (i = 0; unsigned_int(i) < surfind.size(); i++)
1532  {
1533  cout << " " << surfind[i];
1534  }
1535  }
1536  cout << endl;
1537 }
1538 
1539 void surf::disp() const
1540 {
1541  int i;
1542  cout << "surf : index " << index << " | fill " << fill << ", " << target << ", " << error << " | isBorder "
1543  << isBorder << " | voluind " << voluind.size() << ":";
1544  for (i = 0; unsigned_int(i) < voluind.size(); i++)
1545  {
1546  cout << " " << voluind[i];
1547  }
1548  cout << " | edgeind " << edgeind.size() << ":";
1549  for (i = 0; unsigned_int(i) < edgeind.size(); i++)
1550  {
1551  cout << " " << edgeind[i];
1552  }
1553  cout << endl;
1554 }
1555 
1556 void edge::disp() const
1557 {
1558  int i;
1559  cout << "edge : index " << index << " | isBorder " << isBorder << " | vertind " << vertind.size() << ":";
1560  for (i = 0; unsigned_int(i) < vertind.size(); i++)
1561  {
1562  cout << " " << vertind[i];
1563  }
1564  cout << " | surfind " << surfind.size() << ":";
1565  for (i = 0; unsigned_int(i) < surfind.size(); i++)
1566  {
1567  cout << " " << surfind[i];
1568  }
1569  cout << endl;
1570 }
1571 
1572 void vert::disp() const
1573 {
1574  int i;
1575  cout << "vert : index " << index << " | isBorder " << isBorder << " | edgeind " << edgeind.size() << ":";
1576  for (i = 0; unsigned_int(i) < edgeind.size(); i++)
1577  {
1578  cout << " " << edgeind[i];
1579  }
1580  cout << " | coord " << coord.size() << ":";
1581  for (i = 0; unsigned_int(i) < coord.size(); i++)
1582  {
1583  cout << " " << coord[i];
1584  }
1585  cout << endl;
1586 }
1587 
1588 // Class function definitions
1589 // Methods of meshpart : volu surf edge vert
1590 void volu::disptree(const mesh &meshin, int n) const
1591 {
1592  int i;
1593  for (i = 0; i < n; i++)
1594  {
1595  cout << " ";
1596  }
1597  disp();
1598  if (n > 0 && surfind.size() < 8)
1599  {
1600  for (i = 0; unsigned_int(i) < surfind.size(); i++)
1601  {
1602  meshin.surfs.isearch(surfind[i])->disptree(meshin, n - 1);
1603  }
1604  }
1605 }
1606 
1607 void surf::disptree(const mesh &meshin, int n) const
1608 {
1609  int i;
1610  for (i = 0; i < n; i++)
1611  {
1612  cout << " ";
1613  }
1614  disp();
1615  if (n > 0)
1616  {
1617  for (i = 0; unsigned_int(i) < edgeind.size(); i++)
1618  {
1619  meshin.edges.isearch(edgeind[i])->disptree(meshin, n - 1);
1620  }
1621  for (i = 0; unsigned_int(i) < voluind.size(); i++)
1622  {
1623  if (voluind[i] > 0)
1624  {
1625  meshin.volus.isearch(voluind[i])->disptree(meshin, n - 1);
1626  }
1627  }
1628  }
1629 }
1630 
1631 void edge::disptree(const mesh &meshin, int n) const
1632 {
1633  int i;
1634  for (i = 0; i < n; i++)
1635  {
1636  cout << " ";
1637  }
1638  disp();
1639  if (n > 0)
1640  {
1641  for (i = 0; unsigned_int(i) < vertind.size(); i++)
1642  {
1643  meshin.verts.isearch(vertind[i])->disptree(meshin, n - 1);
1644  }
1645  for (i = 0; unsigned_int(i) < surfind.size(); i++)
1646  {
1647  meshin.surfs.isearch(surfind[i])->disptree(meshin, n - 1);
1648  }
1649  }
1650 }
1651 
1652 void vert::disptree(const mesh &meshin, int n) const
1653 {
1654  int i;
1655  for (i = 0; i < n; i++)
1656  {
1657  cout << " ";
1658  }
1659  disp();
1660  if (n > 0)
1661  {
1662  for (i = 0; unsigned_int(i) < edgeind.size(); i++)
1663  {
1664  meshin.edges.isearch(edgeind[i])->disptree(meshin, n - 1);
1665  }
1666  }
1667 }
1668 
1669 double volu::value(const mesh &meshin) const
1670 {
1671  double val = 0.0;
1672  double valMult = this->surfind.size() > 0 ? 1.0 / double(this->surfind.size()) : 0.0;
1673  for (auto vi : this->surfind)
1674  {
1675  val += meshin.surfs.isearch(vi)->value(meshin);
1676  }
1677  return val * valMult;
1678 }
1679 
1680 double surf::value(const mesh &meshin) const
1681 {
1682  double val = 0.0;
1683  double valMult = this->edgeind.size() > 0 ? 1.0 / double(this->edgeind.size()) : 0.0;
1684  for (auto vi : this->edgeind)
1685  {
1686  val += meshin.edges.isearch(vi)->value(meshin);
1687  }
1688  return val * valMult;
1689 }
1690 
1691 double edge::value(const mesh &meshin) const
1692 {
1693  double val = 0.0;
1694  double valMult = this->vertind.size() > 0 ? 1.0 / double(this->vertind.size()) : 0.0;
1695  for (auto vi : this->vertind)
1696  {
1697  val += meshin.verts.isearch(vi)->value(meshin);
1698  }
1699  return val * valMult;
1700 }
1701 
1702 #pragma GCC diagnostic push
1703 #pragma GCC diagnostic ignored "-Wunused-parameter"
1704 double vert::value(const mesh &meshin) const
1705 {
1706  double val = 0.0;
1707  for (int j = 0; j < 3; ++j)
1708  {
1709  val += this->coord[j] * pow(10.0, double(j));
1710  }
1711  return val;
1712 }
1713 #pragma GCC diagnostic pop
1714 
1715 bool mesh::CompareVerts(const vert &in1, const vert &in2) const
1716 {
1717  return in1.value(*this) < in2.value(*this);
1718 }
1719 
1720 bool mesh::CompareEdges(const edge &in1, const edge &in2) const
1721 {
1722  return in1.value(*this) < in2.value(*this);
1723 }
1724 
1725 bool mesh::CompareSurfs(const surf &in1, const surf &in2) const
1726 {
1727  return in1.value(*this) < in2.value(*this);
1728 }
1729 
1730 bool mesh::CompareVolus(const volu &in1, const volu &in2) const
1731 {
1732  return in1.value(*this) < in2.value(*this);
1733 }
1734 
1735 // Input and output
1736 void volu::write(FILE *fid) const
1737 {
1738  int i;
1739 
1740  fprintf(fid, "%i %.16lf %.16lf %.16lf %i ", index, fill, target, error, int(isBorder));
1741  fprintf(fid, "%i ", int(surfind.size()));
1742  for (i = 0; unsigned_int(i) < surfind.size(); i++)
1743  {
1744  fprintf(fid, "%i ", surfind[i]);
1745  }
1746  fprintf(fid, "\n");
1747 }
1748 
1749 void surf::write(FILE *fid) const
1750 {
1751  int i;
1752 
1753  fprintf(fid, "%i %.16lf %.16lf %.16lf %i ", index, fill, target, error, int(isBorder));
1754  fprintf(fid, "%i ", int(voluind.size()));
1755  for (i = 0; unsigned_int(i) < voluind.size(); i++)
1756  {
1757  fprintf(fid, "%i ", voluind[i]);
1758  }
1759  fprintf(fid, "%i ", int(edgeind.size()));
1760  for (i = 0; unsigned_int(i) < edgeind.size(); i++)
1761  {
1762  fprintf(fid, "%i ", edgeind[i]);
1763  }
1764  fprintf(fid, "\n");
1765 }
1766 
1767 void edge::write(FILE *fid) const
1768 {
1769  int i;
1770 
1771  fprintf(fid, "%i %i ", index, int(isBorder));
1772  fprintf(fid, "%i ", int(vertind.size()));
1773  for (i = 0; unsigned_int(i) < vertind.size(); i++)
1774  {
1775  fprintf(fid, "%i ", vertind[i]);
1776  }
1777  fprintf(fid, "%i ", int(surfind.size()));
1778  for (i = 0; unsigned_int(i) < surfind.size(); i++)
1779  {
1780  fprintf(fid, "%i ", surfind[i]);
1781  }
1782  fprintf(fid, "\n");
1783 }
1784 
1785 void vert::write(FILE *fid) const
1786 {
1787  int i;
1788 
1789  fprintf(fid, "%i %i ", index, int(isBorder));
1790  fprintf(fid, "%i ", int(edgeind.size()));
1791  for (i = 0; unsigned_int(i) < edgeind.size(); i++)
1792  {
1793  fprintf(fid, "%i ", edgeind[i]);
1794  }
1795  fprintf(fid, "%i ", int(coord.size()));
1796  for (i = 0; unsigned_int(i) < coord.size(); i++)
1797  {
1798  fprintf(fid, "%.16lf ", coord[i]);
1799  }
1800  fprintf(fid, "\n");
1801 }
1802 
1803 void volu::read(FILE *fid)
1804 {
1805  int i, n;
1806 
1807  fscanf(fid, "%i %lf %lf %lf %i ", &index, &fill, &target, &error, &i);
1808  isBorder = bool(i);
1809  fscanf(fid, "%i ", &n);
1810  surfind.assign(n, 0);
1811  for (i = 0; unsigned_int(i) < surfind.size(); i++)
1812  {
1813  fscanf(fid, "%i ", &surfind[i]);
1814  }
1815 }
1816 
1817 void surf::read(FILE *fid)
1818 {
1819  int i, n;
1820 
1821  fscanf(fid, "%i %lf %lf %lf %i ", &index, &fill, &target, &error, &i);
1822  isBorder = bool(i);
1823  fscanf(fid, "%i ", &n);
1824  voluind.assign(n, 0);
1825  for (i = 0; unsigned_int(i) < voluind.size(); i++)
1826  {
1827  fscanf(fid, "%i ", &voluind[i]);
1828  }
1829  fscanf(fid, "%i ", &n);
1830  edgeind.assign(n, 0);
1831  for (i = 0; unsigned_int(i) < edgeind.size(); i++)
1832  {
1833  fscanf(fid, "%i ", &edgeind[i]);
1834  }
1835 }
1836 
1837 void edge::read(FILE *fid)
1838 {
1839  int i, n;
1840 
1841  fscanf(fid, "%i %i ", &index, &i);
1842  isBorder = bool(i);
1843  fscanf(fid, "%i ", &n);
1844  vertind.assign(n, 0);
1845  for (i = 0; unsigned_int(i) < vertind.size(); i++)
1846  {
1847  fscanf(fid, "%i ", &vertind[i]);
1848  }
1849  fscanf(fid, "%i ", &n);
1850  surfind.assign(n, 0);
1851  for (i = 0; unsigned_int(i) < surfind.size(); i++)
1852  {
1853  fscanf(fid, "%i ", &surfind[i]);
1854  }
1855 }
1856 
1857 void vert::read(FILE *fid)
1858 {
1859  int i, n;
1860 
1861  fscanf(fid, "%i %i ", &index, &i);
1862  isBorder = bool(i);
1863  fscanf(fid, "%i ", &n);
1864  edgeind.assign(n, 0);
1865  for (i = 0; unsigned_int(i) < edgeind.size(); i++)
1866  {
1867  fscanf(fid, "%i ", &edgeind[i]);
1868  }
1869  fscanf(fid, "%i ", &n);
1870  coord.assign(n, 0);
1871  for (i = 0; unsigned_int(i) < coord.size(); i++)
1872  {
1873  fscanf(fid, "%lf ", &coord[i]);
1874  }
1875 }
1876 
1877 std::vector<int> vert::elmind(const mesh &meshin, int dimOveride) const
1878 {
1879  std::vector<int> elmind;
1880  elmind.reserve(30);
1881  int dim = meshin.WhatDim();
1882  if (dimOveride > 0)
1883  {
1884  dim = dimOveride;
1885  }
1886  if (dim == 3)
1887  for (auto edgeInd : this->edgeind)
1888  {
1889  for (auto surfInd : meshin.edges.isearch(edgeInd)->surfind)
1890  {
1891  for (auto voluInd : meshin.surfs.isearch(surfInd)->voluind)
1892  {
1893  elmind.push_back(voluInd);
1894  }
1895  }
1896  }
1897  else
1898  {
1899  for (auto edgeInd : this->edgeind)
1900  {
1901  for (auto surfInd : meshin.edges.isearch(edgeInd)->surfind)
1902  {
1903  elmind.push_back(surfInd);
1904  }
1905  }
1906  }
1907  sort(elmind);
1908  unique(elmind);
1909  return elmind;
1910 }
1911 
1919 std::vector<int> volu::vertind(const mesh &meshin) const
1920 {
1921  std::vector<int> vertind;
1922  vertind.reserve(30);
1923  for (auto surfInd : this->surfind)
1924  {
1925  for (auto edgeInd : meshin.surfs.isearch(surfInd)->edgeind)
1926  {
1927  for (auto vertInd : meshin.edges.isearch(edgeInd)->vertind)
1928  {
1929  vertind.push_back(vertInd);
1930  }
1931  }
1932  }
1933  sort(vertind);
1934  unique(vertind);
1935  return vertind;
1936 }
1937 std::vector<int> surf::vertind(const mesh &meshin) const
1938 {
1939  std::vector<int> vertind;
1940  vertind.reserve(30);
1941 
1942  for (auto edgeInd : this->edgeind)
1943  {
1944  for (auto vertInd : meshin.edges.isearch(edgeInd)->vertind)
1945  {
1946  vertind.push_back(vertInd);
1947  }
1948  }
1949 
1950  sort(vertind);
1951  unique(vertind);
1952  return vertind;
1953 }
1954 
1955 #pragma GCC diagnostic push
1956 #pragma GCC diagnostic ignored "-Wunused-parameter"
1957 void volu::ChangeIndices(int nVert, int nEdge, int nSurf, int nVolu)
1958 {
1959  int i;
1960  index += nVolu;
1961  for (i = 0; unsigned_int(i) < surfind.size(); i++)
1962  {
1963  surfind[i] = (surfind[i] > 0) ? (surfind[i] + nSurf) : surfind[i];
1964  }
1965 }
1966 void surf::ChangeIndices(int nVert, int nEdge, int nSurf, int nVolu)
1967 {
1968  int i;
1969  index += nSurf;
1970  for (i = 0; unsigned_int(i) < voluind.size(); i++)
1971  {
1972  voluind[i] = (voluind[i] > 0) ? (voluind[i] + nVolu) : voluind[i];
1973  }
1974 
1975  for (i = 0; unsigned_int(i) < edgeind.size(); i++)
1976  {
1977  edgeind[i] = edgeind[i] + nEdge;
1978  }
1979 }
1980 void edge::ChangeIndices(int nVert, int nEdge, int nSurf, int nVolu)
1981 {
1982  int i;
1983  index += nEdge;
1984  for (i = 0; unsigned_int(i) < vertind.size(); i++)
1985  {
1986  vertind[i] = vertind[i] + nVert;
1987  }
1988 
1989  for (i = 0; unsigned_int(i) < surfind.size(); i++)
1990  {
1991  surfind[i] = (surfind[i] > 0) ? (surfind[i] + nSurf) : surfind[i];
1992  }
1993 }
1994 void vert::ChangeIndices(int nVert, int nEdge, int nSurf, int nVolu)
1995 {
1996  int i;
1997  index += nVert;
1998  for (i = 0; unsigned_int(i) < edgeind.size(); i++)
1999  {
2000  edgeind[i] = edgeind[i] + nEdge;
2001  }
2002 }
2003 void mesh::TightenConnectivity()
2004 {
2005  verts.TightenConnectivity();
2006  surfs.TightenConnectivity();
2007  edges.TightenConnectivity();
2008  volus.TightenConnectivity();
2009  this->facesAreOriented = false;
2010 }
2011 
2012 void mesh::SwitchIndex(int typeInd, int oldInd, int newInd, const vector<int> &scopeInd)
2013 {
2014  /*Switch the indices of an element for another in all the appropriate
2015  connectivity lists.
2016 
2017  Args:
2018  typeInd [1-8]: type of index */
2019  int ii, jj, kk, newSub, oldSub;
2020  vector<int> subList;
2021  HashedVector<int, int> tempSub;
2022  bool is3DMesh = volus.size() > 0;
2023 
2024  if (typeInd == 1)
2025  { // Switch out a vertex
2026  newSub = verts.find(newInd);
2027  oldSub = verts.find(oldInd);
2028  subList = edges.find_list(verts[oldSub].edgeind);
2029  for (ii = 0; ii < int(subList.size()); ++ii)
2030  { // update vertind
2031  jj = edges(subList[ii])->vertind[1] == oldInd;
2032  edges[subList[ii]].vertind[jj] = newInd;
2033  // update vertex edgeind
2034  verts[newSub].edgeind.push_back(edges[subList[ii]].index);
2035  for (jj = 0; jj < int(verts(oldSub)->edgeind.size()); ++jj)
2036  {
2037  if (verts(oldSub)->edgeind[jj] == edges[subList[ii]].index)
2038  {
2039  verts[oldSub].edgeind.erase(verts[oldSub].edgeind.begin() + jj);
2040  jj--;
2041  }
2042  }
2043  }
2044  sort(verts[newSub].edgeind);
2045  unique(verts[newSub].edgeind);
2046  if (meshDepIsSet && meshDim == 0)
2047  {
2048  meshtree.elemind[oldSub] = newInd;
2049  }
2050  // Hashing has not been invalidated
2051  edges.isHash = 1;
2052  verts.isHash = 1;
2053  }
2054  else if (typeInd == 2)
2055  {
2056  newSub = edges.find(newInd);
2057  oldSub = edges.find(oldInd);
2058  subList = verts.find_list(edges(edges.find(oldInd))->vertind);
2059  for (ii = 0; ii < int(subList.size()); ++ii)
2060  {
2061  for (jj = 0; jj < int(verts(subList[ii])->edgeind.size()); ++jj)
2062  {
2063  if (verts(subList[ii])->edgeind[jj] == oldInd)
2064  {
2065  verts[subList[ii]].edgeind[jj] = newInd;
2066  }
2067  }
2068  }
2069  // Changes the indices of
2070  subList = surfs.find_list(edges(edges.find(oldInd))->surfind);
2071  for (ii = 0; ii < int(subList.size()); ++ii)
2072  {
2073  if (subList[ii] != -1 || is3DMesh)
2074  {
2075  for (jj = 0; jj < int(surfs(subList[ii])->edgeind.size()); ++jj)
2076  {
2077  if (surfs(subList[ii])->edgeind[jj] == oldInd)
2078  {
2079  surfs[subList[ii]].edgeind[jj] = newInd;
2080  edges[newSub].surfind.push_back(surfs[subList[ii]].index);
2081  surfs[subList[ii]].isordered = false;
2082  }
2083  }
2084  }
2085  }
2086 
2087  if (meshDepIsSet && meshDim == 1)
2088  {
2089  meshtree.elemind[oldSub] = newInd;
2090  }
2091 
2092  edges.isHash = 1;
2093  verts.isHash = 1;
2094  surfs.isHash = 1;
2095  edges.isSetMI = 1;
2096  verts.isSetMI = 1;
2097  surfs.isSetMI = 1;
2098  }
2099  else if (typeInd == 3)
2100  {
2101  newSub = surfs.find(newInd);
2102  oldSub = surfs.find(oldInd);
2103  subList = edges.find_list(surfs(surfs.find(oldInd))->edgeind);
2104  for (ii = 0; ii < int(subList.size()); ++ii)
2105  {
2106  for (jj = 0; jj < int(edges(subList[ii])->surfind.size()); ++jj)
2107  {
2108  if (edges(subList[ii])->surfind[jj] == oldInd)
2109  {
2110  edges[subList[ii]].surfind[jj] = newInd;
2111  surfs[newSub].edgeind.push_back(edges[subList[ii]].index);
2112  }
2113  }
2114  }
2115  surfs.isHash = 1;
2116 
2117  subList = volus.find_list(surfs(surfs.find(oldInd))->voluind);
2118  for (ii = 0; ii < int(subList.size()); ++ii)
2119  {
2120  if (subList[ii] != -1)
2121  {
2122  for (jj = 0; jj < int(volus(subList[ii])->surfind.size()); ++jj)
2123  {
2124  if (volus(subList[ii])->surfind[jj] == oldInd)
2125  {
2126  volus[subList[ii]].surfind[jj] = newInd;
2127  surfs[newSub].voluind.push_back(volus[subList[ii]].index);
2128  }
2129  }
2130  }
2131  }
2132 
2133  if (meshDepIsSet && meshDim == 2)
2134  {
2135  // for (ii=0;ii<int(oldSub.size());++ii){
2136  // meshtree.elemind[oldSub[ii]]=newInd;
2137  // }
2138  meshtree.elemind[oldSub] = newInd;
2139  }
2140 
2141  surfs[newSub].isordered = false;
2142  surfs.isHash = 1;
2143  edges.isHash = 1;
2144  volus.isHash = 1;
2145  surfs.isSetMI = 1;
2146  edges.isSetMI = 1;
2147  volus.isSetMI = 1;
2148  }
2149  else if (typeInd == 4)
2150  {
2151  newSub = volus.find(newInd);
2152  oldSub = volus.find(oldInd);
2153  subList = surfs.find_list(volus[volus.find(oldInd)].surfind);
2154  for (ii = 0; ii < int(subList.size()); ++ii)
2155  { // update vertind
2156  for (jj = 0; jj < int(surfs(subList[ii])->voluind.size()); ++jj)
2157  {
2158  if (surfs[subList[ii]].voluind[jj] == oldInd)
2159  {
2160  surfs[subList[ii]].voluind[jj] = newInd;
2161  // update vertex edgeind
2162  volus[newSub].surfind.push_back(surfs[subList[ii]].index);
2163  }
2164  }
2165  }
2166  if (meshDepIsSet && meshDim == 3)
2167  {
2168  // for (ii=0;ii<int(oldSub.size());++ii){
2169  // meshtree.elemind[oldSub[ii]]=newInd;
2170  // }
2171  meshtree.elemind[oldSub] = newInd;
2172  }
2173  // Hashing has not been invalidated
2174  volus.isHash = 1;
2175  surfs.isHash = 1;
2176  volus.isSetMI = 1;
2177  surfs.isSetMI = 1;
2178  }
2179  else if (typeInd == 5)
2180  { // Modify vertex index in scoped mode
2181 
2182  newSub = verts.find(newInd);
2183  oldSub = verts.find(oldInd);
2184 
2185  subList = edges.find_list(scopeInd);
2186  tempSub.vec = edges.find_list(verts(oldSub)->edgeind);
2187  tempSub.GenerateHash();
2188  for (ii = 0; ii < int(subList.size()); ++ii)
2189  {
2190  if (tempSub.find(subList[ii]) != -1)
2191  {
2192  for (jj = 0; jj < int(edges(subList[ii])->vertind.size()); ++jj)
2193  {
2194  if (edges(subList[ii])->vertind[jj] == oldInd)
2195  {
2196  edges[subList[ii]].vertind[jj] = newInd;
2197  verts[newSub].edgeind.push_back(edges[subList[ii]].index);
2198  for (kk = 0; kk < int(verts(oldSub)->edgeind.size()); ++kk)
2199  {
2200  if (verts(oldSub)->edgeind[kk] == edges[subList[ii]].index)
2201  {
2202  verts[oldSub].edgeind.erase(verts[oldSub].edgeind.begin() + kk);
2203  kk--;
2204  }
2205  }
2206  }
2207  }
2208  }
2209  }
2210  if (meshDepIsSet && meshDim == 0)
2211  {
2212  meshtree.elemind[oldSub] = newInd;
2213  }
2214  edges.isHash = 1;
2215  verts.isHash = 1;
2216  edges.isSetMI = 1;
2217  verts.isSetMI = 1;
2218  }
2219  else if (typeInd == 6)
2220  { // Modify surface index in scoped mode
2221 
2222  newSub = surfs.find(newInd);
2223  oldSub = surfs.find(oldInd);
2224 
2225  subList = edges.find_list(scopeInd);
2226  for (ii = 0; ii < int(subList.size()); ++ii)
2227  {
2228  for (jj = 0; jj < int(edges(subList[ii])->surfind.size()); ++jj)
2229  {
2230  if (edges(subList[ii])->surfind[jj] == oldInd)
2231  {
2232  edges[subList[ii]].surfind[jj] = newInd;
2233  surfs[newSub].edgeind.push_back(edges[subList[ii]].index);
2234  for (kk = 0; kk < int(surfs(oldSub)->edgeind.size()); ++kk)
2235  {
2236  if (surfs(oldSub)->edgeind[kk] == edges[subList[ii]].index)
2237  {
2238  surfs[oldSub].edgeind.erase(surfs[oldSub].edgeind.begin() + kk);
2239  kk--;
2240  }
2241  }
2242  }
2243  }
2244  }
2245  for (ii = 0; ii < int(surfs(newSub)->voluind.size()); ii++)
2246  {
2247  if (surfs(newSub)->voluind[ii] > 0)
2248  {
2249  volus.elems[volus.find(surfs(newSub)->voluind[ii])].surfind.push_back(newInd);
2250  }
2251  }
2252  if (meshDepIsSet && meshDim == 2)
2253  {
2254  meshtree.elemind[oldSub] = newInd;
2255  }
2256  edges.isHash = 1;
2257  surfs.isHash = 1;
2258  edges.isSetMI = 1;
2259  surfs.isSetMI = 1;
2260  }
2261  else if (typeInd == 7)
2262  { // Modify volume index in scoped mode
2263 
2264  newSub = volus.find(newInd);
2265  oldSub = volus.find(oldInd);
2266 
2267  subList = surfs.find_list(scopeInd);
2268  for (ii = 0; ii < int(subList.size()); ++ii)
2269  {
2270  for (jj = 0; jj < int(surfs(subList[ii])->voluind.size()); ++jj)
2271  {
2272  if (surfs(subList[ii])->voluind[jj] == oldInd)
2273  {
2274  surfs[subList[ii]].voluind[jj] = newInd;
2275  volus[newSub].surfind.push_back(surfs[subList[ii]].index);
2276  for (kk = 0; kk < int(volus(oldSub)->surfind.size()); ++kk)
2277  {
2278  if (volus(oldSub)->surfind[kk] == surfs[subList[ii]].index)
2279  {
2280  volus[oldSub].surfind.erase(volus[oldSub].surfind.begin() + kk);
2281  kk--;
2282  }
2283  }
2284  }
2285  }
2286  }
2287 
2288  if (meshDepIsSet && meshDim == 3)
2289  {
2290  meshtree.elemind[oldSub] = newInd;
2291  }
2292  surfs.isHash = 1;
2293  volus.isHash = 1;
2294  surfs.isSetMI = 1;
2295  volus.isSetMI = 1;
2296  }
2297  else
2298  {
2299  cerr << "Error unknown type " << typeInd
2300  << " of object for "
2301  "index switching"
2302  << endl;
2303  cerr << "Error in " << __PRETTY_FUNCTION__ << endl;
2304  RSVS3D_ERROR_ARGUMENT(" Type is out of range");
2305  }
2306 }
2307 
2308 void mesh::RemoveIndex(int typeInd, int oldInd)
2309 {
2310  int ii, jj, sub;
2311  vector<int> subList;
2312 
2313  if (typeInd == 1)
2314  {
2315  sub = verts.find(oldInd);
2316  subList = edges.find_list(verts(sub)->edgeind);
2317  for (ii = 0; ii < int(subList.size()); ++ii)
2318  {
2319  for (jj = 0; jj < int(edges(subList[ii])->vertind.size()); ++jj)
2320  {
2321  if (edges(subList[ii])->vertind[jj] == oldInd)
2322  {
2323  edges[subList[ii]].vertind.erase(edges[subList[ii]].vertind.begin() + jj);
2324  jj--;
2325  }
2326  }
2327  }
2328  edges.isHash = 1;
2329  verts.isHash = 1;
2330  edges.isSetMI = 1;
2331  verts.isSetMI = 1;
2332  }
2333  else if (typeInd == 2)
2334  {
2335  sub = edges.find(oldInd);
2336  subList = verts.find_list(edges(sub)->vertind);
2337  for (ii = 0; ii < int(subList.size()); ++ii)
2338  {
2339  for (jj = 0; jj < int(verts(subList[ii])->edgeind.size()); ++jj)
2340  {
2341  if (verts(subList[ii])->edgeind[jj] == oldInd)
2342  {
2343  verts[subList[ii]].edgeind.erase(verts[subList[ii]].edgeind.begin() + jj);
2344  jj--;
2345  }
2346  }
2347  }
2348 
2349  subList = surfs.find_list(edges(sub)->surfind);
2350  for (ii = 0; ii < int(subList.size()); ++ii)
2351  {
2352  if (subList[ii] != -1)
2353  {
2354  for (jj = 0; jj < int(surfs(subList[ii])->edgeind.size()); ++jj)
2355  {
2356  if (surfs(subList[ii])->edgeind[jj] == oldInd)
2357  {
2358  surfs[subList[ii]].edgeind.erase(surfs[subList[ii]].edgeind.begin() + jj);
2359  surfs[subList[ii]].isordered = false;
2360  jj--;
2361  }
2362  }
2363  }
2364  }
2365  edges[sub].vertind.clear();
2366  edges[sub].surfind.clear();
2367 
2368  edges.isHash = 1;
2369  verts.isHash = 1;
2370  surfs.isHash = 1;
2371  edges.isSetMI = 1;
2372  verts.isSetMI = 1;
2373  surfs.isSetMI = 1;
2374  }
2375  else if (typeInd == 3)
2376  {
2377  sub = surfs.find(oldInd);
2378 
2379  subList = edges.find_list(surfs(sub)->edgeind);
2380  for (ii = 0; ii < int(subList.size()); ++ii)
2381  {
2382  for (jj = 0; jj < int(edges(subList[ii])->surfind.size()); ++jj)
2383  {
2384  if (edges(subList[ii])->surfind[jj] == oldInd)
2385  {
2386  edges[subList[ii]].surfind.erase(edges[subList[ii]].surfind.begin() + jj);
2387  jj--;
2388  }
2389  }
2390  }
2391 
2392  subList = volus.find_list(surfs(sub)->voluind);
2393  for (ii = 0; ii < int(subList.size()); ++ii)
2394  {
2395  if (subList[ii] != -1)
2396  {
2397  for (jj = 0; jj < int(volus(subList[ii])->surfind.size()); ++jj)
2398  {
2399  if (volus(subList[ii])->surfind[jj] == oldInd)
2400  {
2401  volus[subList[ii]].surfind.erase(volus[subList[ii]].surfind.begin() + jj);
2402  jj--;
2403  }
2404  }
2405  }
2406  }
2407 
2408  surfs[sub].edgeind.clear();
2409  surfs[sub].voluind.clear();
2410  surfs.isHash = 1;
2411  edges.isHash = 1;
2412  volus.isHash = 1;
2413  surfs.isSetMI = 1;
2414  edges.isSetMI = 1;
2415  volus.isSetMI = 1;
2416  }
2417  else if (typeInd == 4)
2418  {
2419  sub = volus.find(oldInd);
2420 
2421  subList = surfs.find_list(volus(sub)->surfind);
2422  for (ii = 0; ii < int(subList.size()); ++ii)
2423  {
2424  for (jj = 0; jj < int(surfs(subList[ii])->voluind.size()); ++jj)
2425  {
2426  if (surfs(subList[ii])->voluind[jj] == oldInd)
2427  {
2428  surfs[subList[ii]].voluind.erase(surfs[subList[ii]].voluind.begin() + jj);
2429  if (surfs[subList[ii]].voluind.size() < 2)
2430  {
2431  surfs[subList[ii]].voluind.push_back(0);
2432  }
2433  jj--;
2434  }
2435  }
2436  }
2437 
2438  volus[sub].surfind.clear();
2439  surfs.isHash = 1;
2440  volus.isHash = 1;
2441  surfs.isSetMI = 1;
2442  volus.isSetMI = 1;
2443  }
2444  else if (typeInd == 5)
2445  { // Modify vertex index in scoped mode
2446 
2447  RSVS3D_ERROR("Not implemented: Cannot modify vertex in scoped mode.");
2448  }
2449  else
2450  {
2451  cerr << "Error unknown type of object for index switching" << endl;
2452  cerr << "Error in " << __PRETTY_FUNCTION__ << endl;
2453  RSVS3D_ERROR_ARGUMENT(" : Type is out of range");
2454  }
2455 }
2456 
2457 int mesh::TestConnectivity(const char *strRoot) const
2458 {
2459  int ii, jj, kk, kk2, errCount, errTot;
2460  vector<int> testSub;
2461 
2462  errCount = 0;
2463  errTot = 0;
2464  kk = int(verts.size());
2465  for (ii = 0; ii < kk; ++ii)
2466  {
2467  if (verts(ii)->edgeind.size() == 0)
2468  {
2469  errCount++;
2470  cerr << " Test Connectivity Error :" << errCount << " vertex " << verts(ii)->index
2471  << " Has empty connectivity list ";
2472  cerr << endl;
2473  }
2474  else
2475  {
2476 #ifdef RSVS_DIAGNOSTIC
2477  if (verts(ii)->edgeind.size() == 2)
2478  {
2479  errCount++;
2480  cerr << " Test Connectivity Error :" << errCount << " vertex " << verts(ii)->index
2481  << " Has connectivity "
2482  "list of length 2 ";
2483  DisplayVector(verts(ii)->edgeind);
2484  cerr << endl;
2485  }
2486 #endif
2487  testSub = edges.find_list(verts(ii)->edgeind);
2488  kk2 = testSub.size();
2489  for (jj = 0; jj < kk2; ++jj)
2490  {
2491  if (testSub[jj] < 0 && verts(ii)->edgeind[jj] != 0)
2492  {
2493  errCount++;
2494  cerr << " Test Connectivity Error :" << errCount << " vertex " << verts(ii)->index
2495  << " makes unknown reference to edge " << verts(ii)->edgeind[jj] << " list: ";
2496  DisplayVector(verts(ii)->edgeind);
2497  cerr << endl;
2498  }
2499  }
2500  }
2501  }
2502  if (errCount > 0)
2503  {
2504  cerr << "Test Connectivity vertex (edgeind) Errors :" << errCount << endl;
2505  }
2506 
2507  errTot += errCount;
2508  errCount = 0;
2509  kk = int(edges.size());
2510  for (ii = 0; ii < kk; ++ii)
2511  {
2512  testSub = verts.find_list(edges(ii)->vertind);
2513  kk2 = testSub.size();
2514  for (jj = 0; jj < kk2; ++jj)
2515  {
2516  if (testSub[jj] < 0 && edges(ii)->vertind[jj] != 0)
2517  {
2518  errCount++;
2519  cerr << " Test Connectivity Error :" << errCount << " edge " << edges(ii)->index
2520  << " makes unknown reference to vertex " << edges(ii)->vertind[jj] << " list: ";
2521  DisplayVector(edges(ii)->vertind);
2522  cerr << endl;
2523  }
2524  }
2525  }
2526  if (errCount > 0)
2527  {
2528  cerr << "Test Connectivity edges (vertind) Errors :" << errCount << endl;
2529  }
2530 
2531  errTot += errCount;
2532  errCount = 0;
2533  for (ii = 0; ii < kk; ++ii)
2534  {
2535  testSub = surfs.find_list(edges(ii)->surfind);
2536  kk2 = testSub.size();
2537  for (jj = 0; jj < kk2; ++jj)
2538  {
2539  if (testSub[jj] < 0 && edges(ii)->surfind[jj] != 0)
2540  {
2541  errCount++;
2542  cerr << " Test Connectivity Error :" << errCount << " edge " << edges(ii)->index
2543  << " makes unknown reference to surface " << edges(ii)->surfind[jj] << endl;
2544  }
2545  }
2546  }
2547  if (errCount > 0)
2548  {
2549  cerr << "Test Connectivity edges (surfind) Errors :" << errCount << endl;
2550  }
2551 
2552  errTot += errCount;
2553  errCount = 0;
2554  kk = int(surfs.size());
2555  for (ii = 0; ii < kk; ++ii)
2556  {
2557  testSub = edges.find_list(surfs(ii)->edgeind);
2558  kk2 = testSub.size();
2559  for (jj = 0; jj < kk2; ++jj)
2560  {
2561  if (testSub[jj] < 0)
2562  {
2563  errCount++;
2564  cerr << " Test Connectivity Error :" << errCount << " surf " << surfs(ii)->index
2565  << " makes unknown reference to edge " << surfs(ii)->edgeind[jj] << endl;
2566  }
2567  }
2568  if (int(testSub.size()) == 0)
2569  {
2570  errCount++;
2571  cerr << " Test Connectivity Error :" << errCount << " surf " << surfs(ii)->index << " has empty edgeind "
2572  << endl;
2573  }
2574  }
2575  if (errCount > 0)
2576  {
2577  cerr << "Test Connectivity surfs (edgeind) Errors :" << errCount << endl;
2578  }
2579 
2580  errTot += errCount;
2581  errCount = 0;
2582  kk = int(surfs.size());
2583  for (ii = 0; ii < kk; ++ii)
2584  {
2585  testSub = volus.find_list(surfs(ii)->voluind);
2586  kk2 = testSub.size();
2587  for (jj = 0; jj < kk2; ++jj)
2588  {
2589  if (testSub[jj] < 0 && surfs(ii)->voluind[jj] != 0)
2590  {
2591  errCount++;
2592  cerr << " Test Connectivity Error :" << errCount << " surf " << surfs(ii)->index
2593  << " makes unknown reference to volu " << surfs(ii)->voluind[jj] << endl;
2594  }
2595  }
2596  }
2597  if (errCount > 0)
2598  {
2599  cerr << "Test Connectivity surfs (voluind) Errors :" << errCount << endl;
2600  }
2601 
2602  errTot += errCount;
2603  errCount = 0;
2604  kk = int(volus.size());
2605  for (ii = 0; ii < kk; ++ii)
2606  {
2607  testSub = surfs.find_list(volus(ii)->surfind);
2608  kk2 = testSub.size();
2609  for (jj = 0; jj < kk2; ++jj)
2610  {
2611  if (testSub[jj] < 0 && volus(ii)->surfind[jj] != 0)
2612  {
2613  errCount++;
2614  cerr << " Test Connectivity Error :" << errCount << " volu " << volus(ii)->index
2615  << " makes unknown reference to surface " << volus(ii)->surfind[jj] << endl;
2616  }
2617  }
2618  }
2619  if (errCount > 0)
2620  {
2621  cerr << "Test Connectivity volus (surfind) Errors :" << errCount << endl;
2622  }
2623  errTot += errCount;
2624  if (errTot > 0)
2625  {
2626  cerr << errTot
2627  << " Total errors were detected in the connectivity "
2628  "list in: "
2629  << endl
2630  << strRoot << endl;
2631  }
2632  return (errTot);
2633 }
2634 
2635 int mesh::TestConnectivityBiDir(const char *strRoot, bool emptyIsErr) const
2636 {
2637  int ii, jj, ll, ll2, kk, kk2, errCount, errTot, errCountBiDir, errTotBiDir;
2638  bool flag;
2639  vector<int> testSub;
2640 
2641  errCount = 0;
2642  errCountBiDir = 0;
2643  errTot = 0;
2644  errTotBiDir = 0;
2645  kk = int(verts.size());
2646  for (ii = 0; ii < kk; ++ii)
2647  {
2648  if (emptyIsErr && verts(ii)->edgeind.size() == 0)
2649  {
2650  errCount++;
2651  cerr << " Test Connectivity Error :" << errCount << " vertex " << verts(ii)->index
2652  << " Has empty connectivity list ";
2653  cerr << endl;
2654  }
2655  else
2656  {
2657  testSub = edges.find_list(verts(ii)->edgeind);
2658  kk2 = testSub.size();
2659  for (jj = 0; jj < kk2; ++jj)
2660  {
2661  if (testSub[jj] < 0 && verts(ii)->edgeind[jj] != 0)
2662  {
2663  errCount++;
2664  cerr << " Test Connectivity Error :" << errCount << " vertex " << verts(ii)->index
2665  << " makes unknown reference to edge " << verts(ii)->edgeind[jj] << " list: ";
2666  DisplayVector(verts(ii)->edgeind);
2667  cerr << endl;
2668  }
2669  else if (verts(ii)->edgeind[jj] != 0)
2670  {
2671  ll2 = edges(testSub[jj])->vertind.size();
2672  flag = false;
2673  for (ll = 0; ll < ll2; ll++)
2674  {
2675  flag = flag || (edges(testSub[jj])->vertind[ll] == verts(ii)->index);
2676  }
2677  if (!flag)
2678  {
2679  errCountBiDir++;
2680  cerr << " Test Connectivity Error :" << errCountBiDir << " vertex " << verts(ii)->index
2681  << " makes uni-directional reference to edge " << verts(ii)->edgeind[jj] << " list: ";
2682  DisplayVector(verts(ii)->edgeind);
2683  cout << " list (edge.vertind): ";
2684  DisplayVector(edges(jj)->vertind);
2685  cerr << endl;
2686  }
2687  }
2688  }
2689  }
2690  }
2691  if (errCount > 0)
2692  {
2693  cerr << "Test Connectivity vertex (edgeind) Errors :" << errCount << endl;
2694  }
2695  if (errCountBiDir > 0)
2696  {
2697  cerr << "Test Connectivity vertex (edgeind) uni-directional Errors :" << errCountBiDir << endl;
2698  }
2699 
2700  errTot += errCount;
2701  errTotBiDir += errCountBiDir;
2702  errCount = 0;
2703  errCountBiDir = 0;
2704  kk = int(edges.size());
2705  for (ii = 0; ii < kk; ++ii)
2706  {
2707  testSub = verts.find_list(edges(ii)->vertind);
2708  kk2 = testSub.size();
2709  if (emptyIsErr && testSub.size() != 2)
2710  { // Vertind should be of size 2
2711  errCount++;
2712  cerr << " Test Connectivity Error :" << errCount << " edge " << edges(ii)->index
2713  << " has vertind of length " << testSub.size() << " list (edge::vertind): ";
2714  DisplayVector(edges(ii)->vertind);
2715  cerr << endl;
2716  }
2717  for (jj = 0; jj < kk2; ++jj)
2718  {
2719  if (testSub[jj] < 0 && edges(ii)->vertind[jj] != 0)
2720  {
2721  errCount++;
2722  cerr << " Test Connectivity Error :" << errCount << " edge " << edges(ii)->index
2723  << " makes unknown reference to vertex " << edges(ii)->vertind[jj] << " list: ";
2724  DisplayVector(edges(ii)->vertind);
2725  cerr << endl;
2726  }
2727  else if (edges(ii)->vertind[jj] != 0)
2728  {
2729  ll2 = verts(testSub[jj])->edgeind.size();
2730  flag = false;
2731  for (ll = 0; ll < ll2; ll++)
2732  {
2733  flag = flag || (verts(testSub[jj])->edgeind[ll] == edges(ii)->index);
2734  }
2735  if (!flag)
2736  {
2737  errCountBiDir++;
2738  cerr << " Test Connectivity Error :" << errCountBiDir << " edge " << edges(ii)->index
2739  << " makes uni-directional reference to vertex " << edges(ii)->vertind[jj] << " list: ";
2740  DisplayVector(edges(ii)->vertind);
2741  cout << " list (vert.edgeind): ";
2742  DisplayVector(verts(jj)->edgeind);
2743  cerr << endl;
2744  }
2745  }
2746  }
2747  }
2748  if (errCount > 0)
2749  {
2750  cerr << "Test Connectivity edges (vertind) Errors :" << errCount << endl;
2751  }
2752  if (errCountBiDir > 0)
2753  {
2754  cerr << "Test Connectivity edges (vertind) uni-directional Errors :" << errCountBiDir << endl;
2755  }
2756 
2757  errTot += errCount;
2758  errTotBiDir += errCountBiDir;
2759  errCount = 0;
2760  errCountBiDir = 0;
2761  for (ii = 0; ii < kk; ++ii)
2762  {
2763  testSub = surfs.find_list(edges(ii)->surfind);
2764  kk2 = testSub.size();
2765  for (jj = 0; jj < kk2; ++jj)
2766  {
2767  if (testSub[jj] < 0 && edges(ii)->surfind[jj] != 0)
2768  {
2769  errCount++;
2770  cerr << " Test Connectivity Error :" << errCount << " edge " << edges(ii)->index
2771  << " makes unknown reference to surface " << edges(ii)->surfind[jj] << endl;
2772  }
2773  else if (edges(ii)->surfind[jj] != 0)
2774  {
2775  ll2 = surfs(testSub[jj])->edgeind.size();
2776  flag = false;
2777  for (ll = 0; ll < ll2; ll++)
2778  {
2779  flag = flag || (surfs(testSub[jj])->edgeind[ll] == edges(ii)->index);
2780  }
2781  if (!flag)
2782  {
2783  errCountBiDir++;
2784  cerr << " Test Connectivity Error :" << errCountBiDir << " edge " << edges(ii)->index
2785  << " makes uni-directional reference to surface " << edges(ii)->surfind[jj] << " list: ";
2786  DisplayVector(edges(ii)->surfind);
2787  cout << " list (surf.edgeind): ";
2788  DisplayVector(surfs(jj)->edgeind);
2789  cerr << endl;
2790  }
2791  }
2792  }
2793  }
2794  if (errCount > 0)
2795  {
2796  cerr << "Test Connectivity edges (surfind) Errors :" << errCount << endl;
2797  }
2798  if (errCountBiDir > 0)
2799  {
2800  cerr << "Test Connectivity edges (surfind) uni-directional Errors :" << errCountBiDir << endl;
2801  }
2802 
2803  errTot += errCount;
2804  errTotBiDir += errCountBiDir;
2805  errCount = 0;
2806  errCountBiDir = 0;
2807  kk = int(surfs.size());
2808  for (ii = 0; ii < kk; ++ii)
2809  {
2810  testSub = edges.find_list(surfs(ii)->edgeind);
2811  kk2 = testSub.size();
2812  if (int(testSub.size()) == 0)
2813  {
2814  errCount++;
2815  cerr << " Test Connectivity Error :" << errCount << " surf " << surfs(ii)->index << " has empty edgeind "
2816  << endl;
2817  }
2818  for (jj = 0; jj < kk2; ++jj)
2819  {
2820  if (testSub[jj] < 0)
2821  {
2822  errCount++;
2823  cerr << " Test Connectivity Error :" << errCount << " surf " << surfs(ii)->index
2824  << " makes unknown reference to edge " << surfs(ii)->edgeind[jj] << endl;
2825  }
2826  else if (surfs(ii)->edgeind[jj] != 0)
2827  {
2828  ll2 = edges(testSub[jj])->surfind.size();
2829  flag = false;
2830  for (ll = 0; ll < ll2; ll++)
2831  {
2832  flag = flag || (edges(testSub[jj])->surfind[ll] == surfs(ii)->index);
2833  }
2834  if (!flag)
2835  {
2836  errCountBiDir++;
2837  cerr << " Test Connectivity Error :" << errCountBiDir << " surf " << surfs(ii)->index
2838  << " makes uni-directional reference to edge " << surfs(ii)->edgeind[jj] << " list: ";
2839  DisplayVector(surfs(ii)->edgeind);
2840  cout << " list (edge.surfind): ";
2841  DisplayVector(edges(jj)->surfind);
2842  cerr << endl;
2843  }
2844  }
2845  }
2846  }
2847  if (errCount > 0)
2848  {
2849  cerr << "Test Connectivity surfs (edgeind) Errors :" << errCount << endl;
2850  }
2851  if (errCountBiDir > 0)
2852  {
2853  cerr << "Test Connectivity surfs (edgeind) uni-directional Errors :" << errCountBiDir << endl;
2854  }
2855 
2856  errTot += errCount;
2857  errTotBiDir += errCountBiDir;
2858  errCount = 0;
2859  errCountBiDir = 0;
2860  kk = int(surfs.size());
2861  for (ii = 0; ii < kk; ++ii)
2862  {
2863  testSub = volus.find_list(surfs(ii)->voluind);
2864  kk2 = testSub.size();
2865  if (this->WhatDim() > 2 && emptyIsErr && kk2 != 2)
2866  { // voluind should be of size 2
2867  errCount++;
2868  cerr << " Test Connectivity Error :" << errCount << " surf " << surfs(ii)->index
2869  << " has voluind of length " << kk2 << " list (surf::voluind): ";
2870  DisplayVector(surfs(ii)->voluind);
2871  cerr << endl;
2872  }
2873  for (jj = 0; jj < kk2; ++jj)
2874  {
2875  if (testSub[jj] < 0 && surfs(ii)->voluind[jj] != 0)
2876  {
2877  errCount++;
2878  cerr << " Test Connectivity Error :" << errCount << " surf " << surfs(ii)->index
2879  << " makes unknown reference to volu " << surfs(ii)->voluind[jj] << endl;
2880  }
2881  else if (surfs(ii)->voluind[jj] != 0)
2882  {
2883  ll2 = volus(testSub[jj])->surfind.size();
2884  flag = false;
2885  for (ll = 0; ll < ll2; ll++)
2886  {
2887  flag = flag || (volus(testSub[jj])->surfind[ll] == surfs(ii)->index);
2888  }
2889  if (!flag)
2890  {
2891  errCountBiDir++;
2892  cerr << " Test Connectivity Error :" << errCountBiDir << " surf " << surfs(ii)->index
2893  << " makes uni-directional reference to volume " << surfs(ii)->voluind[jj] << " list: ";
2894  DisplayVector(surfs(ii)->voluind);
2895  cout << " list (volu.surfind): ";
2896  DisplayVector(volus(jj)->surfind);
2897  cerr << endl;
2898  }
2899  }
2900  }
2901  }
2902  if (errCount > 0)
2903  {
2904  cerr << "Test Connectivity surfs (voluind) Errors :" << errCount << endl;
2905  }
2906  if (errCountBiDir > 0)
2907  {
2908  cerr << "Test Connectivity surfs (voluind) uni-directional Errors :" << errCountBiDir << endl;
2909  }
2910 
2911  errTot += errCount;
2912  errTotBiDir += errCountBiDir;
2913  errCount = 0;
2914  errCountBiDir = 0;
2915  kk = int(volus.size());
2916  for (ii = 0; ii < kk; ++ii)
2917  {
2918  testSub = surfs.find_list(volus(ii)->surfind);
2919  kk2 = testSub.size();
2920  for (jj = 0; jj < kk2; ++jj)
2921  {
2922  if (testSub[jj] < 0 && volus(ii)->surfind[jj] != 0)
2923  {
2924  errCount++;
2925  cerr << " Test Connectivity Error :" << errCount << " volu " << volus(ii)->index
2926  << " makes unknown reference to surface " << volus(ii)->surfind[jj] << endl;
2927  }
2928  else if (volus(ii)->surfind[jj] != 0)
2929  {
2930  ll2 = surfs(testSub[jj])->voluind.size();
2931  flag = false;
2932  for (ll = 0; ll < ll2; ll++)
2933  {
2934  flag = flag || (surfs(testSub[jj])->voluind[ll] == volus(ii)->index);
2935  }
2936  if (!flag)
2937  {
2938  errCountBiDir++;
2939  cerr << " Test Connectivity Error :" << errCountBiDir << " volu " << volus(ii)->index
2940  << " makes uni-directional reference to surface " << volus(ii)->surfind[jj] << " list: ";
2941  DisplayVector(volus(ii)->surfind);
2942  cout << " list (surfs.voluind): ";
2943  DisplayVector(surfs(testSub[jj])->voluind);
2944  cerr << endl;
2945  }
2946  }
2947  }
2948  }
2949  if (errCount > 0)
2950  {
2951  cerr << "Test Connectivity volus (surfind) Errors :" << errCount << endl;
2952  }
2953  if (errCountBiDir > 0)
2954  {
2955  cerr << "Test Connectivity volus (surfind) uni-directional Errors :" << errCountBiDir << endl;
2956  }
2957  errTot += errCount;
2958  errTotBiDir += errCountBiDir;
2959  if (errTot > 0)
2960  {
2961  cerr << errTot
2962  << " Total errors were detected in the "
2963  "connectivity list in: "
2964  << endl
2965  << strRoot << endl;
2966  }
2967  if (errTotBiDir > 0)
2968  {
2969  cerr << errTotBiDir
2970  << " Total errors were detected in "
2971  "the bi-directionality of the connectivity list in: "
2972  << endl
2973  << strRoot << endl;
2974  }
2975  return (errTot);
2976 }
2977 
2978 #pragma GCC diagnostic pop
2979 // methods for mesh
2980 void mesh::HashArray()
2981 {
2982  verts.HashArray();
2983  edges.HashArray();
2984  surfs.HashArray();
2985  volus.HashArray();
2986 }
2987 void mesh::SetMaxIndex()
2988 {
2989  verts.SetMaxIndex();
2990  edges.SetMaxIndex();
2991  surfs.SetMaxIndex();
2992  volus.SetMaxIndex();
2993 }
2994 void mesh::SetLastIndex()
2995 {
2996  verts.SetLastIndex();
2997  edges.SetLastIndex();
2998  surfs.SetLastIndex();
2999  volus.SetLastIndex();
3000 }
3001 
3002 void mesh::ArraysAreHashed()
3003 {
3004  this->verts.isHash = 1;
3005  this->edges.isHash = 1;
3006  this->surfs.isHash = 1;
3007  this->volus.isHash = 1;
3008 }
3009 void mesh::SetEdgeLengths()
3010 {
3011  int nEdges = int(this->edges.size());
3012  bool setEdgeLengths = true;
3013  for (int ii = 0; ii < nEdges; ++ii)
3014  {
3015  if (!rsvs3d::constants::__issetlength(this->edges(ii)->GetLength(false)))
3016  {
3017  // if (this->edges(ii)->vertind[0] == 0
3018  // && this->edges(ii)->vertind[1] == 0) {
3019  // setEdgeLengths = false;
3020  // break;
3021  // } else {
3022  this->edges.elems[ii].SetLength(*this);
3023  // }
3024  }
3025  }
3026  this->edgesLengthsAreSet = setEdgeLengths;
3027 }
3028 void mesh::PrepareForUse(bool needOrder)
3029 {
3030  verts.isInMesh = true;
3031  edges.isInMesh = true;
3032  surfs.isInMesh = true;
3033  volus.isInMesh = true;
3034 
3035  if (meshDim == 0)
3036  {
3037  meshDim = 3;
3038  if (volus.size() == 0)
3039  {
3040  meshDim--;
3041  if (surfs.size() == 0)
3042  {
3043  meshDim--;
3044  if (edges.size() == 0)
3045  {
3046  meshDim--;
3047  }
3048  }
3049  }
3050  }
3051 
3052  verts.PrepareForUse();
3053  edges.PrepareForUse();
3054  surfs.PrepareForUse();
3055  volus.PrepareForUse();
3056  // Additional mesh preparation steps
3057  // if(!meshDepIsSet){
3058  // SetMeshDepElm();
3059  // }
3060 
3061  if (!borderIsSet)
3062  {
3063  this->SetBorders();
3064  }
3065  if (needOrder)
3066  {
3067  this->OrderEdges();
3068  }
3069  verts.ForceArrayReady();
3070  edges.ForceArrayReady();
3071  surfs.ForceArrayReady();
3072  volus.ForceArrayReady();
3073  if (!this->edgesLengthsAreSet)
3074  {
3075  try
3076  {
3077  this->SetEdgeLengths();
3078  }
3079  catch (exception const &ex)
3080  {
3081  RSVS3D_ERROR_NOTHROW(" Error setting Edge lengths.\n Note this can "
3082  "be due to a call to mesh::PrepareForUse before edges[].vertind"
3083  " has been set, use mesh::HashArray instead if");
3084  }
3085  }
3086 }
3087 void mesh::InvalidateEdgeLength(int iEdge)
3088 {
3089  if (!this->edges.isHash)
3090  {
3091  this->edges.HashArray();
3092  }
3093  int eSub = this->edges.find(iEdge);
3094  this->edges.elems[eSub].InvalidateLength();
3095  this->edgesLengthsAreSet = false;
3096 }
3097 
3098 void mesh::GetMaxIndex(int *nVert, int *nEdge, int *nSurf, int *nVolu) const
3099 {
3100  *nVert = verts.GetMaxIndex();
3101  *nEdge = edges.GetMaxIndex();
3102  *nSurf = surfs.GetMaxIndex();
3103  *nVolu = volus.GetMaxIndex();
3104 }
3105 void mesh::disp() const
3106 {
3107  verts.disp();
3108  edges.disp();
3109  surfs.disp();
3110  volus.disp();
3111 }
3112 void mesh::read(FILE *fid)
3113 {
3114  verts.read(fid);
3115  edges.read(fid);
3116  surfs.read(fid);
3117  volus.read(fid);
3118 
3119  verts.isInMesh = true;
3120  edges.isInMesh = true;
3121  surfs.isInMesh = true;
3122  volus.isInMesh = true;
3123 }
3124 void mesh::write(FILE *fid) const
3125 {
3126  // fprintf(fid,"%i \n",int(borderIsSet));
3127  verts.write(fid);
3128  edges.write(fid);
3129  surfs.write(fid);
3130  volus.write(fid);
3131 }
3132 int mesh::read(const char *str)
3133 {
3134  // Convenience read function taking a single char argument
3135  FILE *fid;
3136  fid = fopen(str, "r");
3137  if (fid != NULL)
3138  {
3139  this->read(fid);
3140  fclose(fid);
3141  }
3142  else
3143  {
3144  cout << "File " << str << "Could not be opened to read" << endl;
3145  return (1);
3146  }
3147  return (0);
3148 }
3149 int mesh::write(const char *str) const
3150 {
3151  FILE *fid;
3152  fid = fopen(str, "w");
3153  if (fid != NULL)
3154  {
3155  this->write(fid);
3156  fclose(fid);
3157  }
3158  else
3159  {
3160  cout << "File " << str << "Could not be opened to write" << endl;
3161  return (1);
3162  }
3163  return (0);
3164 }
3165 bool mesh::isready() const
3166 {
3167  bool readyforuse = true;
3168  readyforuse = readyforuse & verts.isready();
3169  readyforuse = readyforuse & edges.isready();
3170  readyforuse = readyforuse & surfs.isready();
3171  readyforuse = readyforuse & volus.isready();
3172 
3173  return (readyforuse);
3174 }
3175 
3176 void mesh::displight() const
3177 {
3178  cout << "mesh: vert " << verts.size();
3179  cout << "; edges " << edges.size();
3180  cout << "; surfs " << surfs.size();
3181  cout << "; volus " << volus.size() << endl;
3182 }
3183 void mesh::size(int &nVe, int &nE, int &nS, int &nVo) const
3184 {
3185  nVe = this->verts.size();
3186  nE = this->edges.size();
3187  nS = this->surfs.size();
3188  nVo = this->volus.size();
3189 }
3190 
3191 void mesh::Init(int nVe, int nE, int nS, int nVo)
3192 {
3193  borderIsSet = false;
3194  meshDim = 0;
3195  verts.Init(nVe);
3196  edges.Init(nE);
3197  surfs.Init(nS);
3198  volus.Init(nVo);
3199 
3200  verts.isInMesh = true;
3201  edges.isInMesh = true;
3202  surfs.isInMesh = true;
3203  volus.isInMesh = true;
3204 
3205 #ifdef TEST_ARRAYSTRUCTURES
3206  cout << "Mesh Correctly Assigned!" << endl;
3207 #endif // TEST_ARRAYSTRUCTURES
3208 }
3209 
3210 void mesh::reserve(int nVe, int nE, int nS, int nVo)
3211 {
3212  verts.reserve(nVe);
3213  edges.reserve(nE);
3214  surfs.reserve(nS);
3215  volus.reserve(nVo);
3216 
3217  verts.isInMesh = true;
3218  edges.isInMesh = true;
3219  surfs.isInMesh = true;
3220  volus.isInMesh = true;
3221 }
3222 
3223 void mesh::MakeCompatible_inplace(mesh &other) const
3224 {
3225  // Makes other mesh compatible with this to be
3226  // merged without index crashes
3227 
3228  int nVert, nEdge, nSurf, nVolu;
3229 
3230  // Define Max indices in current mesh
3231  this->GetMaxIndex(&nVert, &nEdge, &nSurf, &nVolu);
3232  other.ChangeIndices(nVert, nEdge, nSurf, nVolu);
3233 }
3234 
3235 void mesh::ChangeIndices(int nVert, int nEdge, int nSurf, int nVolu)
3236 {
3237  volus.ChangeIndices(nVert, nEdge, nSurf, nVolu);
3238  edges.ChangeIndices(nVert, nEdge, nSurf, nVolu);
3239  surfs.ChangeIndices(nVert, nEdge, nSurf, nVolu);
3240  verts.ChangeIndices(nVert, nEdge, nSurf, nVolu);
3241 }
3242 
3243 mesh mesh::MakeCompatible(mesh other) const
3244 {
3245  MakeCompatible_inplace(other);
3246  return (other);
3247 }
3248 
3249 void mesh::Concatenate(const mesh &other)
3250 {
3251  this->volus.Concatenate(other.volus);
3252  this->edges.Concatenate(other.edges);
3253  this->verts.Concatenate(other.verts);
3254  this->surfs.Concatenate(other.surfs);
3255 }
3256 
3257 void mesh::PopulateIndices()
3258 {
3259  volus.PopulateIndices();
3260  edges.PopulateIndices();
3261  verts.PopulateIndices();
3262  surfs.PopulateIndices();
3263  meshDepIsSet = false;
3264 }
3265 
3266 // Field Specific operations
3267 
3285 #pragma GCC diagnostic push
3286 #pragma GCC diagnostic ignored "-Wunused-parameter"
3287 int OrderEdgeList(vector<int> &edgeind, const mesh &meshin, bool warn, bool errout, const vector<int> *edgeIndOrigPtr,
3288  const surf *surfin)
3289 {
3290  unordered_multimap<int, int> vert2Edge;
3291  vector<bool> isDone;
3292  vector<int> edgeIndOrig;
3293  int vertCurr, edgeCurr, ii, jj, endsExpl = 0;
3294 
3295  if (edgeind.size() <= 0)
3296  {
3297  return (rsvsorder::ordered);
3298  }
3299  // edgeIndOrig2=edgeind;
3300  if (edgeIndOrigPtr == NULL)
3301  {
3302  // edgeInOrigPtr is not defined and there is no need
3303  sort(edgeind);
3304  unique(edgeind);
3305  edgeIndOrig = edgeind;
3306  edgeIndOrigPtr = &edgeIndOrig;
3307  }
3308 
3309  isDone.assign(edgeIndOrigPtr->size(), false);
3310  auto edgeSub = meshin.edges.find_list(edgeind);
3311  auto edge2Vert = ConcatenateVectorField(meshin.edges, &edge::vertind, edgeSub);
3312 
3313  HashVector(edge2Vert, vert2Edge);
3314 
3315  vertCurr = edge2Vert[0];
3316  edgeCurr = edgeind[0];
3317  isDone[0] = true;
3318  auto it = vert2Edge.end();
3319  for (ii = 1; ii < int(edgeind.size()); ++ii)
3320  {
3321  auto range = vert2Edge.equal_range(vertCurr);
3322  if (vert2Edge.count(vertCurr) == 1)
3323  {
3324  if (warn || errout)
3325  {
3326  if (errout)
3327  {
3328  cerr << "Error";
3329  }
3330  else
3331  {
3332  cerr << "Warning";
3333  }
3334  cerr << " in :" << __PRETTY_FUNCTION__;
3335  cerr << " - edgeind is not closed (single vertex " << vertCurr << ")" << endl;
3336  if (errout)
3337  {
3338  RSVS3D_ERROR_ARGUMENT("edgelist is not closed");
3339  }
3340  }
3341  if (!endsExpl)
3342  { // explore the one way chain the other way
3343  endsExpl++;
3344  vertCurr = edge2Vert[1];
3345  edgeCurr = edgeind[0];
3346  range = vert2Edge.equal_range(vertCurr);
3347  }
3348  else
3349  { // Exit
3350 
3351  return rsvsorder::open * ii;
3352  }
3353  }
3354 #ifdef SAFE_ACCESS
3355  if (range.first == vert2Edge.end())
3356  {
3357  surfin->disptree(meshin, 0);
3358 
3359  cerr << ii << " vert " << vertCurr << " ";
3360  DisplayVector(edge2Vert);
3361  DisplayVector(edgeind);
3362  meshin.verts.isearch(vertCurr)->disp();
3363  cout << it->second << " " << 1 / 2 << 2 / 3 << endl;
3364  cerr << "Error in :" << __PRETTY_FUNCTION__ << endl;
3365  RSVS3D_ERROR_RANGE("unordered_multimap went beyond its "
3366  "range in OrderEdges");
3367  }
3368 #ifdef RSVS_DIAGNOSTIC
3369  if (vert2Edge.count(vertCurr) != 2)
3370  {
3371  cerr << "DIAGNOSTIC in " << __PRETTY_FUNCTION__ << endl;
3372  cerr << " current vertex " << vertCurr << " appears " << vert2Edge.count(vertCurr)
3373  << " in the surf::edgeind ...->vertind" << endl;
3374  }
3375 #endif // RSVS_DIAGNOSTIC
3376 #endif // SAFE_ACCESS
3377  jj = (*edgeIndOrigPtr)[(range.first->second) / 2] == edgeCurr;
3378 
3379  it = range.first;
3380  if (jj)
3381  {
3382  ++it;
3383  }
3384  if (!isDone[(it->second) / 2])
3385  {
3386  isDone[(it->second) / 2] = true;
3387  edgeCurr = (*edgeIndOrigPtr)[(it->second) / 2];
3388  // Warning ((x/2)*2) not necessarily equal x
3389  // Done to round down to the nearest even
3390  jj = edge2Vert[((it->second) / 2) * 2] == vertCurr;
3391  vertCurr = edge2Vert[((it->second) / 2) * 2 + jj];
3392  edgeind[ii] = edgeCurr;
3393  }
3394  else if (endsExpl)
3395  {
3396  return rsvsorder::open * ii;
3397  }
3398  else
3399  {
3400 #ifdef RSVS_DIAGNOSTIC_FIXED
3401  cerr << "DIAGNOSTIC in " << __PRETTY_FUNCTION__
3402  << " surface about to be truncated, if "
3403  "this should not be the case"
3404  " this can be due to duplicates in the edgeind list"
3405  << endl;
3406  cerr << "edgeind : ";
3407  DisplayVector(edgeind);
3408  cerr << endl << "edgeIndOrig : ";
3409  DisplayVector((*edgeIndOrigPtr));
3410  cerr << endl << "Original connectivity setup:" << endl;
3411  auto temp = edgeind;
3412  edgeind = (*edgeIndOrigPtr);
3413  surfin->disptree(meshin, 1);
3414  edgeind = temp;
3415 #endif // RSVS_DIAGNOSTIC
3416 
3417  edgeind.erase(edgeind.begin() + ii, edgeind.end());
3418 
3419 #ifdef RSVS_DIAGNOSTIC_FIXED
3420  cerr << endl << "New connectivity setup:" << endl;
3421  surfin->disptree(meshin, 1);
3422 #endif // RSVS_DIAGNOSTIC
3423 
3424  return rsvsorder::truncated;
3425  break; // Unnecessary
3426  }
3427  }
3428  return rsvsorder::ordered;
3429 }
3430 #pragma GCC diagnostic pop
3431 
3449 int OrderList(vector<int> &edgeind, const vector<int> &edge2Vert, bool warn, bool errout,
3450  const vector<int> *edgeIndOrigPtr)
3451 {
3452  unordered_multimap<int, int> vert2Edge;
3453  vector<bool> isDone;
3454  vector<int> edgeIndOrig;
3455  int vertCurr, edgeCurr, ii, jj, endsExpl = 0;
3456 
3457  if (edgeind.size() <= 0)
3458  {
3459  return (rsvsorder::ordered);
3460  }
3461  // edgeIndOrig2=edgeind;
3462  if (edgeIndOrigPtr == NULL)
3463  {
3464  // edgeInOrigPtr is not defined and there is no need
3465  sort(edgeind);
3466  unique(edgeind);
3467  edgeIndOrig = edgeind;
3468  edgeIndOrigPtr = &edgeIndOrig;
3469  }
3470 
3471  isDone.assign(edgeIndOrigPtr->size(), false);
3472 
3473  HashVector(edge2Vert, vert2Edge);
3474 
3475  vertCurr = edge2Vert[0];
3476  edgeCurr = edgeind[0];
3477  isDone[0] = true;
3478  auto it = vert2Edge.end();
3479  for (ii = 1; ii < int(edgeind.size()); ++ii)
3480  {
3481  auto range = vert2Edge.equal_range(vertCurr);
3482  if (vert2Edge.count(vertCurr) == 1)
3483  {
3484  if (warn || errout)
3485  {
3486  if (errout)
3487  {
3488  cerr << "Error";
3489  }
3490  else
3491  {
3492  cerr << "Warning";
3493  }
3494  cerr << " in :" << __PRETTY_FUNCTION__;
3495  cerr << " - edgeind is not closed (single vertex " << vertCurr << ")" << endl;
3496  if (errout)
3497  {
3498  RSVS3D_ERROR_ARGUMENT("edgelist is not closed");
3499  }
3500  }
3501  if (!endsExpl)
3502  { // explore the one way chain the other way
3503  endsExpl++;
3504  vertCurr = edge2Vert[1];
3505  edgeCurr = edgeind[0];
3506  range = vert2Edge.equal_range(vertCurr);
3507  }
3508  else
3509  { // Exit
3510 
3511  return rsvsorder::open * ii;
3512  }
3513  }
3514 #ifdef SAFE_ACCESS
3515  if (range.first == vert2Edge.end())
3516  {
3517  cerr << ii << " vert " << vertCurr << " ";
3518  DisplayVector(edge2Vert);
3519  DisplayVector(edgeind);
3520  cout << it->second << " " << 1 / 2 << 2 / 3 << endl;
3521  cerr << "Error in :" << __PRETTY_FUNCTION__ << endl;
3522  RSVS3D_ERROR_RANGE("unordered_multimap went beyond its "
3523  "range in OrderEdges");
3524  }
3525 #ifdef RSVS_DIAGNOSTIC
3526  if (vert2Edge.count(vertCurr) != 2)
3527  {
3528  cerr << "DIAGNOSTIC in " << __PRETTY_FUNCTION__ << endl;
3529  cerr << " current vertex " << vertCurr << " appears " << vert2Edge.count(vertCurr)
3530  << " in the surf::edgeind ...->vertind" << endl;
3531  }
3532 #endif // RSVS_DIAGNOSTIC
3533 #endif // SAFE_ACCESS
3534  jj = (*edgeIndOrigPtr)[(range.first->second) / 2] == edgeCurr;
3535 
3536  it = range.first;
3537  if (jj)
3538  {
3539  ++it;
3540  }
3541  if (!isDone[(it->second) / 2])
3542  {
3543  isDone[(it->second) / 2] = true;
3544  edgeCurr = (*edgeIndOrigPtr)[(it->second) / 2];
3545  // Warning ((x/2)*2) not necessarily equal x
3546  // Done to round down to the nearest even
3547  jj = edge2Vert[((it->second) / 2) * 2] == vertCurr;
3548  vertCurr = edge2Vert[((it->second) / 2) * 2 + jj];
3549  edgeind[ii] = edgeCurr;
3550  }
3551  else if (endsExpl)
3552  {
3553  return rsvsorder::open * ii;
3554  }
3555  else
3556  {
3557  edgeind.erase(edgeind.begin() + ii, edgeind.end());
3558  return rsvsorder::truncated;
3559  break; // Unnecessary
3560  }
3561  }
3562  return rsvsorder::ordered;
3563 }
3564 
3565 int vert::OrderEdges(const mesh *meshin, std::vector<int> &edgeIndOut) const
3566 {
3567  int retVal = 0;
3568  vector<int> edge2Vert;
3569 
3570  if (&edgeIndOut != &(this->edgeind))
3571  {
3572  edgeIndOut = this->edgeind;
3573  }
3574  sort(edgeIndOut);
3575  unique(edgeIndOut);
3576  if (edgeIndOut.size() < 2)
3577  {
3578  return rsvs3d::constants::ordering::error;
3579  }
3580  vector<int> edgeIndOrig = edgeIndOut;
3581 
3582  edge2Vert.reserve(edgeIndOut.size() * 2);
3583  for (auto iEdge : edgeIndOut)
3584  {
3585  auto edgeC = meshin->edges.isearch(iEdge);
3586  if (edgeC->surfind.size() != 2)
3587  {
3588  return rsvs3d::constants::ordering::error;
3589  }
3590  edge2Vert.push_back(edgeC->surfind[0]);
3591  edge2Vert.push_back(edgeC->surfind[1]);
3592  }
3593 
3594  retVal = OrderList(edgeIndOut, edge2Vert, false, false, &edgeIndOrig);
3595 
3596  if (retVal != rsvs3d::constants::ordering::ordered)
3597  {
3598  edgeIndOut = edgeIndOrig;
3599  }
3600 
3601  return retVal;
3602 }
3603 
3604 std::pair<std::vector<int>, int> vert::OrderEdges(const mesh *meshin) const
3605 {
3606  std::pair<std::vector<int>, int> output;
3607  vector<int> &edgeIndOut = output.first;
3608 
3609  auto retVal = this->OrderEdges(meshin, edgeIndOut);
3610 
3611  return {edgeIndOut, retVal};
3612 }
3613 
3614 int vert::OrderEdges(const mesh *meshin)
3615 {
3616  return this->OrderEdges(meshin, this->edgeind);
3617 }
3618 
3619 int vert::SurroundingCoords(const mesh *meshin, grid::coordlist &coordout, bool isOrdered,
3620  std::vector<int> *edgeIndOutPtr) const
3621 {
3622  // Faf about to avoid unnecessary allocation into edgeIndOut if not needed
3623  std::vector<int> edgeIndModif;
3624 
3625  const std::vector<int> *edgeIndInPtr = &(this->edgeind);
3626 
3627  coordout.clear();
3628  if (!isOrdered)
3629  {
3630  auto retOrder = this->OrderEdges(meshin, edgeIndModif);
3631  if (!rsvs3d::constants::ordering::__isordered(retOrder))
3632  {
3633  return rsvs3d::constants::__failure;
3634  }
3635  edgeIndInPtr = &edgeIndModif;
3636  }
3637 
3638  // Is a reference to either this->edgeind if isOrdered=true or edgeIndModif
3639  // otherwise.
3640  auto &edgeIndOut = *edgeIndInPtr;
3641 
3642  int nEdges = edgeIndOut.size();
3643  for (int i = 0; i < nEdges; ++i)
3644  {
3645  int iVert = meshin->VertFromVertEdge(this->index, edgeIndOut[i]);
3646  coordout.push_back(&(meshin->verts.isearch(iVert)->coord));
3647  }
3648  // Return the ordered list if a location is provided for it.
3649  if (edgeIndOutPtr != NULL)
3650  {
3651  if (!isOrdered)
3652  {
3653  edgeIndModif.swap(*edgeIndOutPtr);
3654  }
3655  else
3656  {
3657  *edgeIndOutPtr = this->edgeind;
3658  }
3659  }
3660  return rsvs3d::constants::__success;
3661 }
3662 
3663 int surf::OrderEdges(mesh *meshin)
3664 {
3665  vector<int> edgeIndOrig;
3666  vector<bool> isDone;
3667  bool isTruncated;
3668  int newSurfInd;
3669 
3670  isTruncated = false;
3671  newSurfInd = -1;
3672  // do nothing if edgeind is empty
3673  if (meshin == NULL)
3674  {
3675  this->isordered = false;
3676  return (newSurfInd);
3677  }
3678  if (edgeind.size() <= 0)
3679  {
3680  this->isordered = true;
3681  return (newSurfInd);
3682  }
3683  // edgeIndOrig2=edgeind;
3684  sort(this->edgeind);
3685  unique(this->edgeind);
3686  edgeIndOrig = this->edgeind;
3687 
3688  int retFlag = OrderEdgeList(this->edgeind, *meshin, true, true, &edgeIndOrig, this);
3689 
3690  isTruncated = retFlag == rsvsorder::truncated;
3691 
3692  if (!isTruncated)
3693  {
3694  newSurfInd = -1; // No new surface index
3695  this->isordered = true;
3696  return (newSurfInd);
3697  }
3698 
3699  if ((meshin->surfs.capacity() - meshin->surfs.size()) == 0)
3700  {
3701 // Checks that there is space to add a new face if surface truncation
3702 // is in order. If there is no space add space and exit
3703 #ifdef RSVS_DIAGNOSTIC_FIXED
3704  cerr << "DIAGNOSTIC in " << __PRETTY_FUNCTION__ << " reallocation necessary." << endl;
3705 #endif // RSVS_DIAGNOSTIC_FIXED
3706  this->edgeind = edgeIndOrig;
3707  this->isordered = false;
3708  meshin->surfs.reserve(meshin->surfs.capacity() + meshin->surfs.capacity() / 2);
3709  newSurfInd = -1; // No new surface index
3710  return (newSurfInd);
3711  }
3712 
3713  newSurfInd = this->SplitSurface(*meshin, edgeIndOrig);
3714 
3715  this->isordered = true;
3716  return (newSurfInd);
3717 }
3718 
3719 int surf::SplitSurface(mesh &meshin, const vector<int> &fullEdgeInd)
3720 {
3721  int newSurfInd, kk;
3722  // This adds a second surface if the surface closes early
3723  vector<int> newSurfedgeind;
3724  surf newSurf = *this;
3725  meshin.surfs.SetMaxIndex();
3726  newSurf.index = meshin.surfs.GetMaxIndex() + 1;
3727  // newSurf.voluind=voluind;
3728  // gets added to newSurf.edgeind in SwitchIndex
3729  newSurf.edgeind.clear();
3730 
3731  // build new surface edgeind
3732  for (auto allInd : fullEdgeInd)
3733  {
3734  bool flag = false;
3735  for (auto currInd : this->edgeind)
3736  {
3737  flag = currInd == allInd;
3738  if (flag)
3739  {
3740  break;
3741  }
3742  }
3743  if (!flag)
3744  {
3745  newSurf.edgeind.push_back(allInd);
3746  }
3747  }
3748 #ifdef SAFE_ALGO
3749  if ((newSurf.edgeind.size() != (fullEdgeInd.size() - this->edgeind.size())) || newSurf.edgeind.size() == 0 ||
3750  this->edgeind.size() == 0)
3751  {
3752  cerr << "Error in: " << __PRETTY_FUNCTION__ << endl;
3753  cerr << " New surface edgeind is not of the correct size:" << endl
3754  << " newSurf.edgeind (" << newSurf.edgeind.size() << ") != fullEdgeInd (" << fullEdgeInd.size()
3755  << ")-this::edgeind(" << this->edgeind.size() << ")" << endl;
3756  RSVS3D_ERROR_ARGUMENT("Size of edgeind of truncated "
3757  "surface is incorrect.");
3758  }
3759 #endif
3760 #ifdef RSVS_DIAGNOSTIC_FIXED
3761  DisplayVector(this->edgeind);
3762  DisplayVector(newSurf.edgeind);
3763 #endif // RSVS_DIAGNOSTIC_FIXED
3764  // triggers a reallocation invalidating the this pointer
3765  meshin.surfs.push_back(newSurf);
3766  // meshin.surfs(meshin.surfs.size()-1)->disp();
3767  auto prevHash = meshin.surfs.isHash;
3768  meshin.surfs.isHash = 1;
3769  meshin.SwitchIndex(6, this->index, newSurf.index, newSurf.edgeind);
3770 #ifdef SAFE_ALGO
3771  if (this->edgeind.size() == 0)
3772  {
3773  RSVS3D_ERROR_ARGUMENT("surf::edgeind was deleted in "
3774  "surf::SplitSurface process");
3775  }
3776 #endif // SAFE_ALGO
3777  meshin.surfs[meshin.surfs.size() - 1].OrderEdges(&meshin);
3778 
3779  meshin.surfs.isHash = prevHash;
3780  prevHash = meshin.volus.isHash;
3781  if (meshin.WhatDim() > 2)
3782  {
3783 #ifdef SAFE_ACCESS
3784  if (this->voluind.size() < 2)
3785  {
3786  cerr << "Error in " << __PRETTY_FUNCTION__ << endl;
3787  cerr << " voluind is of size " << this->voluind.size() << endl;
3788  RSVS3D_ERROR_LOGIC("surf::voluind should be size 2");
3789  }
3790 #endif // SAFE_ACCESS
3791  for (int i = 0; i < 2; ++i)
3792  {
3793  kk = meshin.volus.find(voluind[i]);
3794  if (kk != -1)
3795  {
3796  meshin.volus[kk].surfind.push_back(newSurf.index);
3797  }
3798  meshin.volus.isHash = prevHash;
3799  }
3800  }
3801  newSurfInd = newSurf.index;
3802 #ifdef RSVS_DIAGNOSTIC_FIXED
3803  cerr << " Succesful surface split " << this->index << " | " << newSurfInd << endl;
3804 #endif
3805  return (newSurfInd);
3806 }
3807 
3808 void surf::OrderedVerts(const mesh *meshin, vector<int> &vertList) const
3809 {
3810  int jj, n, actVert, edgeCurr;
3811  int verts[2], vertsPast[2];
3812 
3813  n = int(edgeind.size());
3814  vertList.clear();
3815  vertList.reserve(n);
3816  // This comes out in the same order as edgeind
3817  edgeCurr = meshin->edges.find(edgeind[n - 1]);
3818  verts[0] = (meshin->edges(edgeCurr)->vertind[0]);
3819  verts[1] = (meshin->edges(edgeCurr)->vertind[1]);
3820  vertsPast[0] = verts[0];
3821  vertsPast[1] = verts[1];
3822 
3823  for (jj = 0; jj < int(n); ++jj)
3824  {
3825  edgeCurr = meshin->edges.find(edgeind[jj]);
3826 
3827  verts[0] = (meshin->edges(edgeCurr)->vertind[0]);
3828  verts[1] = (meshin->edges(edgeCurr)->vertind[1]);
3829 
3830  if ((verts[0] == vertsPast[0]) || (verts[1] == vertsPast[0]))
3831  {
3832  actVert = 0;
3833  }
3834 #ifdef SAFE_ALGO
3835  else if ((verts[0] == vertsPast[1]) || (verts[1] == vertsPast[1]))
3836  {
3837  actVert = 1;
3838  }
3839 #endif // TEST_POSTPROCESSING
3840  else
3841  {
3842  actVert = 1;
3843 #ifdef SAFE_ALGO
3844  cerr << "Error: Surface is not ordered " << endl;
3845  cerr << " in " << __PRETTY_FUNCTION__ << endl;
3846  RSVS3D_ERROR_ARGUMENT("Surface not ordered");
3847 #endif
3848  }
3849 
3850  vertList.push_back(vertsPast[actVert]);
3851  vertsPast[0] = verts[0];
3852  vertsPast[1] = verts[1];
3853  }
3854 }
3855 vector<int> surf::OrderedVerts(const mesh *meshin) const
3856 {
3857  vector<int> vertList;
3858  this->OrderedVerts(meshin, vertList);
3859  return (vertList);
3860 }
3861 
3862 void surf::FlipVolus()
3863 {
3864  int interm;
3865  interm = voluind[0];
3866  voluind[0] = voluind[1];
3867  voluind[1] = interm;
3868 }
3869 
3870 bool edge::vertconneq(const edge &other) const
3871 {
3872  return (this->vertind[0] == other.vertind[0] && this->vertind[1] == other.vertind[1]) ||
3873  (this->vertind[1] == other.vertind[0] && this->vertind[0] == other.vertind[1]);
3874 }
3875 
3876 bool surf::edgeconneq(const surf &other, bool recurse) const
3877 {
3878  /*
3879  Explores all the edgeind combinations looking for a one to one
3880  match with each.
3881 
3882  Boolean recurse controls the recursive behaviour of the function.
3883  The default is true so that a user calling it will get robust
3884  equality check between the connectivity lists. THis is then called by
3885  itself with recurse=false to get the other direction.
3886 
3887  This function is very inneficient at O(2*m*n) but exact, constant, and
3888  requires no memory allocation.
3889  */
3890  bool out, temp;
3891  int count = this->edgeind.size();
3892  int count2 = other.edgeind.size();
3893  out = true;
3894  for (int i = 0; i < count; ++i)
3895  {
3896  temp = false;
3897  for (int j = 0; j < count2; ++j)
3898  {
3899  temp = temp || (this->edgeind[i] == other.edgeind[j]);
3900  }
3901  out = out && temp;
3902  if (!out)
3903  {
3904  break;
3905  }
3906  }
3907  if (recurse)
3908  {
3909  return out && other.edgeconneq(*this, false);
3910  }
3911  else
3912  {
3913  return out;
3914  }
3915 }
3916 
3917 vector<int> mesh::OrderEdges()
3918 {
3919  int ii, kk = 0;
3920  int newInd;
3921  vector<int> newSurfPairs;
3922  // Use the address of the first element to ensure that no reallocation
3923  if (surfs.size() > 0)
3924  {
3925  auto origSurf = surfs(0);
3926  auto capPrev = surfs.capacity();
3927  bool pntrFlag, capFlag;
3928 
3929  do
3930  {
3931  kk++;
3932  origSurf = surfs(0);
3933  capPrev = surfs.capacity();
3934  for (ii = 0; ii < surfs.size(); ++ii)
3935  {
3936  if (!surfs(ii)->isready(true))
3937  {
3938  newInd = surfs.elems[ii].OrderEdges(this);
3939  if (newInd > -1)
3940  {
3941  newSurfPairs.push_back(surfs(ii)->index);
3942  newSurfPairs.push_back(newInd);
3943  }
3944  }
3945  }
3946  // while the vector has been reallocated.
3947  pntrFlag = (origSurf != surfs(0)); // test 1st pntr
3948  capFlag = (capPrev != surfs.capacity());
3949  } while (pntrFlag || capFlag);
3950 #ifdef SAFE_ALGO
3951  for (ii = 0; ii < surfs.size(); ++ii)
3952  {
3953  if (!surfs(ii)->isready(true))
3954  {
3955  RSVS3D_ERROR_LOGIC("After ordering edges a surface"
3956  " is not ordered.");
3957  }
3958  }
3959 #endif // SAFE_ALGO
3960  }
3961  return (newSurfPairs);
3962 }
3963 
3964 void mesh::GetOffBorderVert(vector<int> &vertInd, vector<int> &voluInd, int outerVolume)
3965 {
3966  /*
3967  Gets vertices that are in a vlume that is on the edge of the design
3968  space but off th eedge themselves
3969 
3970  outerVolume indicates the additional condition of the volume needing
3971  to be full or empty in the parents.
3972  -1 return all vertices
3973  0 return vertices where the target volume is 1.0
3974  1 return vertices where the target volume is >0.0
3975  */
3976 
3977  if (!borderIsSet)
3978  {
3979  this->SetBorders();
3980  }
3981  this->GetOffBorderVert(vertInd, voluInd, outerVolume);
3982 }
3983 
3984 void mesh::GetOffBorderVert(vector<int> &vertInd, vector<int> &voluInd, int outerVolume) const
3985 {
3986  if (this->WhatDim() == 3)
3987  {
3988  this->GetOffBorderVert3D(vertInd, voluInd, outerVolume);
3989  }
3990  else if (this->WhatDim() == 2)
3991  {
3992  this->GetOffBorderVert2D(vertInd, voluInd, outerVolume);
3993  }
3994 }
3995 
3996 void mesh::GetOffBorderVert3D(vector<int> &vertInd, vector<int> &voluInd, int outerVolume) const
3997 {
3998  /*
3999  Gets vertices that are in a volume that is on the edge of the design
4000  space but off th eedge themselves
4001 
4002  outerVolume indicates the additional condition of the volume needing
4003  to be full or empty in the parents.
4004  -1 return all vertices
4005  0 return vertices where the target volume is 1.0
4006  1 return vertices where the target volume is >0.0
4007  */
4008  int ii, ni, jj, nj;
4009  vector<double> vals;
4010  bool voluOnBoundary;
4011 
4012  ni = volus.size();
4013  nj = verts.size();
4014  vertInd.clear();
4015  vertInd.reserve(nj);
4016  voluInd.clear();
4017  voluInd.reserve(ni);
4018 
4019  for (ii = 0; ii < ni; ++ii)
4020  {
4021  voluOnBoundary = volus(ii)->isBorder;
4022  if (voluOnBoundary)
4023  {
4024  if (outerVolume == 0)
4025  {
4026  this->VoluValuesofParents(volus(ii)->index, vals, &volu::target);
4027  voluOnBoundary = false;
4028  jj = 0;
4029  while (!voluOnBoundary && jj < meshtree.nParents)
4030  {
4031  voluOnBoundary = fabs(vals[jj] - 1.0) < __DBL_EPSILON__;
4032  ++jj;
4033  }
4034  }
4035  else if (outerVolume == 1)
4036  {
4037  this->VoluValuesofParents(volus(ii)->index, vals, &volu::target);
4038  voluOnBoundary = false;
4039  jj = 0;
4040  while (!voluOnBoundary && jj < meshtree.nParents)
4041  {
4042  voluOnBoundary = fabs(vals[jj]) > __DBL_EPSILON__;
4043  ++jj;
4044  }
4045  }
4046  else if (outerVolume != -1)
4047  {
4048  RSVS3D_ERROR_ARGUMENT("Unkown value of outerVolume -1,0, or 1");
4049  }
4050  }
4051  // THIS IS DODGY HOW to pick the side to delete can fail
4052  if (voluOnBoundary)
4053  {
4054  // Pick one of the volumes to delete
4055  voluInd.push_back(volus(ii)->index);
4056 
4057  for (auto surfAct : volus(ii)->surfind)
4058  {
4059  for (auto edgeAct : surfs.isearch(surfAct)->edgeind)
4060  {
4061  for (auto vertAct : edges.isearch(edgeAct)->vertind)
4062  {
4063  if (!verts.isearch(vertAct)->isBorder)
4064  {
4065  vertInd.push_back(vertAct);
4066  }
4067  }
4068  }
4069  }
4070  }
4071  }
4072 }
4073 
4074 void mesh::GetOffBorderVert2D(vector<int> &vertInd, vector<int> &surfind, int outerVolume) const
4075 {
4076  /*
4077  Gets vertices that are in a vlume that is on the edge of the design
4078  space but off th eedge themselves
4079 
4080  outerVolume indicates the additional condition of the volume needing
4081  to be full or empty in the parents.
4082  -1 return all vertices
4083  0 return vertices where the target volume is 1.0
4084  1 return vertices where the target volume is >0.0
4085  */
4086  int ii, ni, jj, nj, kk, nk, vertTemp, edgeSub, surfSub;
4087  vector<double> vals;
4088  bool surfCond;
4089 
4090  ni = surfs.size();
4091  nj = verts.size();
4092  vertInd.clear();
4093  vertInd.reserve(nj);
4094  surfind.clear();
4095  surfind.reserve(ni);
4096 
4097  for (ii = 0; ii < ni; ++ii)
4098  {
4099  surfCond = surfs(ii)->isBorder;
4100  if (surfCond)
4101  {
4102  if (outerVolume == 0)
4103  {
4104  this->SurfValuesofParents(surfs(ii)->index, vals, &surf::target);
4105  surfCond = false;
4106  jj = 0;
4107  while (!surfCond && jj < meshtree.nParents)
4108  {
4109  surfCond = vals[jj] == 1.0;
4110  ++jj;
4111  }
4112  }
4113  else if (outerVolume == 1)
4114  {
4115  this->SurfValuesofParents(surfs(ii)->index, vals, &surf::target);
4116  surfCond = false;
4117  jj = 0;
4118  while (!surfCond && jj < meshtree.nParents)
4119  {
4120  surfCond = vals[jj] > 0.0;
4121  ++jj;
4122  }
4123  }
4124  else if (outerVolume != -1)
4125  {
4126  RSVS3D_ERROR_ARGUMENT("Unkownn value of "
4127  "outerVolume -1,0, or 1");
4128  }
4129  }
4130  // THIS IS DODGY HOW to pick the side to delete can fail
4131  if (surfCond)
4132  {
4133  // Pick one of the surfaces to delete
4134  if (outerVolume == 0)
4135  {
4136  nj = surfs(ii)->edgeind.size();
4137  for (jj = 0; jj < nj; ++jj)
4138  {
4139  surfSub = edges.find(surfs(ii)->edgeind[jj]);
4140  for (kk = 0; kk < 2; ++kk)
4141  {
4142  if (edges(surfSub)->surfind[kk] != 0)
4143  {
4144  if (!(surfs.isearch(edges(surfSub)->surfind[kk])->isBorder))
4145  {
4146  surfind.push_back(edges(surfSub)->surfind[kk]);
4147  }
4148  }
4149  }
4150  }
4151  }
4152  else
4153  {
4154  surfind.push_back(surfs(ii)->index);
4155  }
4156  surfSub = ii;
4157  nj = surfs(surfSub)->edgeind.size();
4158  for (jj = 0; jj < nj; ++jj)
4159  {
4160  edgeSub = edges.find(surfs(surfSub)->edgeind[jj]);
4161  nk = edges(edgeSub)->vertind.size();
4162  for (kk = 0; kk < nk; ++kk)
4163  {
4164  vertTemp = edges(edgeSub)->vertind[kk];
4165  if (!verts.isearch(vertTemp)->isBorder)
4166  {
4167  vertInd.push_back(vertTemp);
4168  }
4169  }
4170  }
4171  }
4172  }
4173 }
4174 
4175 void mesh::SetBorders()
4176 {
4177  int ii, jj, nT;
4178  if (int(volus.size()) > 0)
4179  {
4180  // Update border status of edges
4181  for (ii = 0; ii < surfs.size(); ++ii)
4182  {
4183  jj = 0;
4184  nT = surfs(ii)->voluind.size();
4185  surfs[ii].isBorder = false;
4186  while (jj < nT && !surfs(ii)->isBorder)
4187  {
4188  surfs[ii].isBorder = surfs[ii].voluind[jj] == 0;
4189  jj++;
4190  }
4191  }
4192  surfs.ForceArrayReady();
4193 
4194  // Update border status of volus
4195  for (ii = 0; ii < volus.size(); ++ii)
4196  {
4197  jj = 0;
4198  nT = volus(ii)->surfind.size();
4199  volus[ii].isBorder = false;
4200  while (jj < nT && !volus(ii)->isBorder)
4201  {
4202  volus[ii].isBorder = surfs(surfs.find(volus[ii].surfind[jj]))->isBorder;
4203  jj++;
4204  }
4205  }
4206  volus.ForceArrayReady();
4207 
4208  // Update border status of edges
4209  for (ii = 0; ii < edges.size(); ++ii)
4210  {
4211  jj = 0;
4212  nT = edges(ii)->surfind.size();
4213  edges[ii].isBorder = false;
4214  while (jj < nT && !edges(ii)->isBorder)
4215  {
4216  edges[ii].isBorder = surfs(surfs.find(edges[ii].surfind[jj]))->isBorder;
4217  jj++;
4218  }
4219  }
4220  edges.ForceArrayReady();
4221  }
4222  else
4223  {
4224  for (ii = 0; ii < edges.size(); ++ii)
4225  {
4226  jj = 0;
4227  nT = edges(ii)->surfind.size();
4228  edges[ii].isBorder = false;
4229  while (jj < nT && !edges(ii)->isBorder)
4230  {
4231  edges[ii].isBorder = (edges[ii].surfind[jj] == 0);
4232  jj++;
4233  }
4234  }
4235  edges.ForceArrayReady();
4236 
4237  for (ii = 0; ii < surfs.size(); ++ii)
4238  {
4239  jj = 0;
4240  nT = surfs(ii)->edgeind.size();
4241  surfs[ii].isBorder = false;
4242  while (jj < nT && !surfs(ii)->isBorder)
4243  {
4244  surfs[ii].isBorder = edges(edges.find(surfs[ii].edgeind[jj]))->isBorder;
4245  jj++;
4246  }
4247  }
4248  surfs.ForceArrayReady();
4249  }
4250 
4251  // Update border status of edges
4252  for (ii = 0; ii < verts.size(); ++ii)
4253  {
4254  jj = 0;
4255  nT = verts(ii)->edgeind.size();
4256  verts[ii].isBorder = false;
4257  while (jj < nT && !verts(ii)->isBorder)
4258  {
4259  verts[ii].isBorder = edges(edges.find(verts[ii].edgeind[jj]))->isBorder;
4260  jj++;
4261  }
4262  }
4263  verts.ForceArrayReady();
4264 
4265  if (int(volus.size()) > 0)
4266  {
4267  // in 3D volume is on the border if any part of it
4268  // is out (incl 1 vert)
4269  int nVolu = volus.size();
4270  for (ii = 0; ii < nVolu; ++ii)
4271  {
4272  if (!volus(ii)->isBorder)
4273  {
4274  for (auto surfAct : volus(ii)->surfind)
4275  {
4276  for (auto edgeAct : surfs.isearch(surfAct)->edgeind)
4277  {
4278  for (auto vertAct : edges.isearch(edgeAct)->vertind)
4279  {
4280  if (verts.isearch(vertAct)->isBorder)
4281  {
4282  volus[ii].isBorder = true;
4283  break;
4284  }
4285  }
4286  if (volus[ii].isBorder)
4287  {
4288  break;
4289  }
4290  }
4291  if (volus[ii].isBorder)
4292  {
4293  break;
4294  }
4295  }
4296  }
4297  }
4298  volus.ForceArrayReady();
4299  }
4300  else
4301  {
4302  // in 2D a surface is on the border if any part of it
4303  // is out (incl 1 vert)
4304  int nSurf = surfs.size();
4305  for (ii = 0; ii < nSurf; ++ii)
4306  {
4307  if (!surfs(ii)->isBorder)
4308  {
4309  for (auto edgeAct : surfs(ii)->edgeind)
4310  {
4311  for (auto vertAct : edges.isearch(edgeAct)->vertind)
4312  {
4313  if (verts.isearch(vertAct)->isBorder)
4314  {
4315  surfs[ii].isBorder = true;
4316  break;
4317  }
4318  }
4319  if (surfs[ii].isBorder)
4320  {
4321  break;
4322  }
4323  }
4324  }
4325  }
4326  surfs.ForceArrayReady();
4327  }
4328  borderIsSet = true;
4329 }
4330 
4331 void mesh::ForceCloseContainers()
4332 {
4333  int ii, jj, iEdge, iSurf, kk;
4334  int nVert, nEdge, nSurf, nBlocks;
4335  bool is3DMesh = volus.size() > 0;
4336  vector<int> vertBlock;
4337  vector<bool> surfsIsDone;
4338 
4339  vertBlock.clear();
4340  nBlocks = this->ConnectedVertex(vertBlock);
4341  surfsIsDone.assign(surfs.size(), false);
4342  nVert = verts.size();
4343  if (is3DMesh)
4344  {
4345  // reassign volumes
4346  volus.elems.clear();
4347  volus.Init(nBlocks);
4348  volus.PopulateIndices();
4349  volus.HashArray();
4350  for (ii = 0; ii < nVert; ii++)
4351  {
4352  nEdge = verts(ii)->edgeind.size();
4353  for (jj = 0; jj < nEdge; ++jj)
4354  {
4355  iEdge = edges.find(verts(ii)->edgeind[jj]);
4356 #ifdef SAFE_ALGO
4357  if (vertBlock[verts.find(edges(iEdge)->vertind[0])] != vertBlock[verts.find(edges(iEdge)->vertind[1])])
4358  {
4359  cerr << endl
4360  << "An edge has connections "
4361  "in 2 vertBlocks:"
4362  << endl;
4363  cerr << __PRETTY_FUNCTION__ << endl;
4364  }
4365 #endif // SAFE_ALGO
4366  nSurf = edges(iEdge)->surfind.size();
4367  for (kk = 0; kk < nSurf; ++kk)
4368  {
4369  iSurf = surfs.find(edges(iEdge)->surfind[kk]);
4370  if (surfsIsDone[iSurf])
4371  {
4372 #ifdef SAFE_ALGO
4373  if (surfs.elems[iSurf].voluind[0] != vertBlock[ii])
4374  {
4375  cerr << endl
4376  << "Surf voluind assignement "
4377  "performed twice during:"
4378  << endl;
4379  cerr << __PRETTY_FUNCTION__ << endl;
4380  }
4381 #endif // SAFE_ALGO
4382  }
4383  volus.elems[volus.find(vertBlock[ii])].surfind.push_back(edges(iEdge)->surfind[kk]);
4384  surfs.elems[iSurf].voluind.clear();
4385  surfs.elems[iSurf].voluind.push_back(vertBlock[ii]);
4386  surfs.elems[iSurf].voluind.push_back(0);
4387  surfsIsDone[iSurf] = true;
4388  }
4389  }
4390  }
4391  }
4392  else
4393  {
4394  // reassign surfaces
4395  surfs.elems.clear();
4396  surfs.Init(nBlocks);
4397  surfs.PopulateIndices();
4398  surfs.HashArray();
4399 
4400  for (ii = 0; ii < nVert; ii++)
4401  {
4402  nEdge = verts(ii)->edgeind.size();
4403  for (jj = 0; jj < nEdge; ++jj)
4404  {
4405  iEdge = edges.find(verts(ii)->edgeind[jj]);
4406  surfs.elems[surfs.find(vertBlock[ii])].edgeind.push_back(verts(ii)->edgeind[jj]);
4407  edges.elems[iEdge].surfind.clear();
4408  edges.elems[iEdge].surfind.push_back(vertBlock[ii]);
4409  edges.elems[iEdge].surfind.push_back(0);
4410  }
4411  }
4412  }
4413 
4414  verts.ForceArrayReady();
4415  surfs.ForceArrayReady();
4416  edges.ForceArrayReady();
4417  volus.ForceArrayReady();
4418 }
4419 
4420 std::vector<int> mesh::MergeGroupedVertices(HashedVector<int, int> &closeVert, bool delVerts)
4421 {
4422  /*
4423  Uses a hashed vector to merge points grouped together.
4424 
4425  Deletes points which have been merged out.
4426  */
4427  std::vector<bool> isSnaxDone;
4428  std::vector<int> sameSnaxs, rmvInds;
4429  int nSnax, countJ, countRep;
4430 
4431  nSnax = closeVert.vec.size();
4432  if (!closeVert.isHash)
4433  {
4434  closeVert.GenerateHash();
4435  }
4436  rmvInds.reserve(nSnax);
4437  isSnaxDone.assign(nSnax, false);
4438 
4439  // Find matching elements and perform the replacement process
4440  // DisplayVector(closeVert.vec);
4441  for (int i = 0; i < nSnax; ++i)
4442  {
4443  if ((!isSnaxDone[i]) && (closeVert.vec[i] != -1))
4444  {
4445  sameSnaxs.clear();
4446  sameSnaxs = closeVert.findall(closeVert.vec[i]);
4447  countJ = sameSnaxs.size();
4448  for (int j = 1; j < countJ; ++j)
4449  {
4450  this->SwitchIndex(1, this->verts(sameSnaxs[j])->index, this->verts(sameSnaxs[0])->index);
4451  countRep++;
4452  rmvInds.push_back(this->verts(sameSnaxs[j])->index);
4453  isSnaxDone[sameSnaxs[j]] = true;
4454  }
4455  isSnaxDone[sameSnaxs[0]] = true;
4456  }
4457  else
4458  {
4459  isSnaxDone[i] = true;
4460  }
4461  }
4462 
4463  if (rmvInds.size() > 0 && delVerts)
4464  {
4465  sort(rmvInds);
4466  unique(rmvInds);
4467  this->verts.remove(rmvInds);
4468  this->verts.PrepareForUse();
4469  }
4470  return (rmvInds);
4471 }
4472 
4473 void mesh::RemoveSingularConnectors(const std::vector<int> &rmvVertInds, bool voidError)
4474 {
4475  /*
4476  Removes degenerate connectors.
4477 
4478  This removes edges, surfaces and volumes which do not have enough
4479  children (ie connector elements of lower dimensionality)
4480  to be a closed container.
4481  Edges < 2 vertices
4482  Surfaces < 3 edges
4483  Volumes < 4 Surfaces
4484 
4485  Offers the option to delete vertices as well.
4486  */
4487 
4488  std::vector<int> rmvInds, rmvInds2;
4489  int nEdgeSurf;
4490  int count, countRep;
4491 
4492  if (rmvVertInds.size() > 0)
4493  {
4494  rmvInds = rmvVertInds;
4495 
4496  sort(rmvInds);
4497  unique(rmvInds);
4498  this->verts.remove(rmvInds);
4499  this->verts.PrepareForUse();
4500 #ifdef RSVS_VERBOSE
4501  std::cout << "Number of removed vertices " << rmvInds.size() << std::endl;
4502 #endif // RSVS_VERBOSE
4503  rmvInds.clear();
4504  }
4505 
4506  // Remove Edges
4507  count = this->edges.size();
4508  countRep = 0;
4509  for (int i = 0; i < count; ++i)
4510  {
4511  if (this->edges(i)->vertind[0] == this->edges(i)->vertind[1])
4512  {
4513  this->RemoveIndex(2, this->edges(i)->index);
4514  rmvInds.push_back(this->edges(i)->index);
4515  countRep++;
4516  }
4517  }
4518 #ifdef RSVS_VERBOSE
4519  std::cout << "Number of removed edges " << countRep << std::endl;
4520 #endif // RSVS_VERBOSE
4521  sort(rmvInds);
4522  unique(rmvInds);
4523  this->edges.remove(rmvInds);
4524  this->edges.PrepareForUse();
4525  rmvInds.clear();
4526 
4527  // Remove Surfs
4528  count = this->surfs.size();
4529  countRep = 0;
4530  rmvInds2.clear();
4531  for (int i = 0; i < count; ++i)
4532  {
4533  nEdgeSurf = this->surfs(i)->edgeind.size();
4534  if (nEdgeSurf == 2)
4535  {
4536  bool edgeConnEq = this->edges.isearch(this->surfs(i)->edgeind[0])
4537  ->vertconneq(*(this->edges.isearch(this->surfs(i)->edgeind[1])));
4538  if (edgeConnEq && (this->surfs(i)->edgeind[1] != this->surfs(i)->edgeind[0]))
4539  {
4540  rmvInds2.push_back(this->surfs(i)->edgeind[1]);
4541  this->SwitchIndex(2, this->surfs(i)->edgeind[1], this->surfs(i)->edgeind[0]);
4542  }
4543  }
4544  if (nEdgeSurf < 3)
4545  {
4546  this->RemoveIndex(3, this->surfs(i)->index);
4547  rmvInds.push_back(this->surfs(i)->index);
4548  countRep++;
4549  }
4550  }
4551 #ifdef RSVS_VERBOSE
4552  std::cout << "Number of removed surfs " << countRep << std::endl;
4553 #endif // RSVS_VERBOSE
4554  sort(rmvInds);
4555  unique(rmvInds);
4556  this->surfs.remove(rmvInds);
4557  this->surfs.PrepareForUse();
4558  rmvInds.clear();
4559  sort(rmvInds2);
4560  unique(rmvInds2);
4561 #ifdef RSVS_VERBOSE
4562  std::cout << "Number of removed edges (duplicates) " << rmvInds2.size() << std::endl;
4563 #endif // RSVS_VERBOSE
4564  this->edges.remove(rmvInds2);
4565  this->edges.PrepareForUse();
4566  rmvInds2.clear();
4567 
4568  // Remove Volus
4569  count = this->volus.size();
4570  countRep = 0;
4571  // std::cout << this->surfs.isHash << " ";
4572  for (int i = 0; i < count; ++i)
4573  {
4574  nEdgeSurf = this->volus(i)->surfind.size();
4575  if (nEdgeSurf == 2)
4576  {
4577  bool surfConnEq = this->surfs.isearch(this->volus(i)->surfind[0])
4578  ->edgeconneq(*(this->surfs.isearch(this->volus(i)->surfind[1])));
4579  // if the surfaces have the same edge connectivities and
4580  // different indices
4581  if ((this->volus(i)->surfind[0] != this->volus(i)->surfind[1]) && surfConnEq)
4582  {
4583  rmvInds2.push_back(this->volus(i)->surfind[1]);
4584  this->SwitchIndex(3, this->volus(i)->surfind[1], this->volus(i)->surfind[0]);
4585  }
4586  }
4587  else if (nEdgeSurf == 3 && voidError)
4588  {
4589  // This case is unhandled as either there is still a degenerate
4590  // face which should not be the case or a void is being created
4591  // which should not be the case either.
4592  RSVS3D_ERROR_LOGIC("Unhandled case - Degenerate face or "
4593  "unwanted Void creation");
4594  }
4595  if (nEdgeSurf < 4)
4596  {
4597  this->RemoveIndex(4, this->volus(i)->index);
4598  rmvInds.push_back(this->volus(i)->index);
4599  countRep++;
4600  }
4601  }
4602 #ifdef RSVS_VERBOSE
4603  std::cout << "Number of removed volus " << countRep << std::endl;
4604 #endif // RSVS_VERBOSE
4605  sort(rmvInds);
4606  unique(rmvInds);
4607  this->volus.remove(rmvInds);
4608  this->volus.PrepareForUse();
4609  rmvInds.clear();
4610  sort(rmvInds2);
4611  unique(rmvInds2);
4612 #ifdef RSVS_VERBOSE
4613  std::cout << "Number of removed surfs (duplicates) " << rmvInds2.size() << std::endl;
4614 #endif // RSVS_VERBOSE
4615  this->surfs.remove(rmvInds2);
4616  this->surfs.PrepareForUse();
4617  rmvInds2.clear();
4618 }
4619 
4633 int mesh::ConnectedVertex(vector<int> &vertBlock) const
4634 {
4635  int nVertExplored, nVerts, nBlocks, nCurr, nEdgesCurr, ii, jj, kk;
4636  vector<bool> vertStatus; // 1 explored 0 not explored
4637 
4638  vector<int> currQueue, nextQueue; // Current and next queues of indices
4639 
4640  // Preparation of the arrays;
4641  nVerts = verts.size();
4642  nBlocks = 0;
4643  nVertExplored = 0;
4644 
4645  vertStatus.assign(nVerts, false);
4646 
4647  if (int(vertBlock.size()) == 0)
4648  {
4649  // Standard behaviour of grouping all connected vertices when vertBlock
4650  // is empty
4651  vertBlock.clear();
4652  vertBlock.assign(nVerts, 0);
4653  }
4654  else if (int(vertBlock.size()) == nVerts)
4655  {
4656  // Treat vertices with non zero value as already processed.
4657  // This allows these vertices to separate blocks of vertices.
4658  for (int i = 0; i < nVerts; ++i)
4659  {
4660  if (vertBlock[i] != 0)
4661  {
4662  vertStatus[i] = true;
4663  nVertExplored++;
4664  }
4665  }
4666  }
4667  else
4668  {
4669  // If vertBlock and nVerts are difference sizes the behaviour is
4670  // undefined.
4671  cerr << "Error in " << __PRETTY_FUNCTION__ << ": " << endl
4672  << "vertBlock should be empty or the size of mesh.verts";
4673  RSVS3D_ERROR_ARGUMENT("vertBlock vector incompatible with mesh.");
4674  }
4675  currQueue.reserve(nVerts / 2);
4676  nextQueue.reserve(nVerts / 2);
4677 
4678  // While Loop, while not all vertices explored
4679  while (nVertExplored < nVerts)
4680  {
4681  // if currQueue is empty start new block
4682  if (currQueue.size() < 1)
4683  {
4684  ii = 0;
4685  while (ii < nVerts && vertStatus[ii])
4686  {
4687  ii++;
4688  }
4689  if (vertStatus[ii])
4690  {
4691  cerr << "Error starting point for loop not found despite "
4692  "max number of vertex not reached"
4693  << endl;
4694  cerr << "Error in " << __PRETTY_FUNCTION__ << endl;
4695  RSVS3D_ERROR_RANGE(" : Starting point for block not found");
4696  }
4697  currQueue.push_back(ii);
4698  nBlocks++;
4699  }
4700  // Explore current queue
4701  nCurr = currQueue.size();
4702  for (ii = 0; ii < nCurr; ++ii)
4703  {
4704  if (!vertStatus[currQueue[ii]])
4705  {
4706  vertBlock[currQueue[ii]] = nBlocks;
4707  nEdgesCurr = verts(currQueue[ii])->edgeind.size();
4708  for (jj = 0; jj < nEdgesCurr; ++jj)
4709  {
4710  kk = int(edges.isearch(verts(currQueue[ii])->edgeind[jj])->vertind[0] ==
4711  verts(currQueue[ii])->index);
4712  nextQueue.push_back(verts.find(edges.isearch(verts(currQueue[ii])->edgeind[jj])->vertind[kk]));
4713 #ifdef SAFE_ALGO
4714  if (verts.find(edges.isearch(verts(currQueue[ii])->edgeind[jj])->vertind[kk]) == -1)
4715  {
4716  cerr << "Edge index: " << verts(currQueue[ii])->edgeind[jj]
4717  << " vertex index:" << edges.isearch(verts(currQueue[ii])->edgeind[jj])->vertind[kk]
4718  << endl;
4719  cerr << "Edge connected to non existant vertex" << endl;
4720  cerr << "Error in " << __PRETTY_FUNCTION__ << endl;
4721  RSVS3D_ERROR_RANGE(" : Vertex not found");
4722  }
4723 #endif
4724  }
4725  vertStatus[currQueue[ii]] = true;
4726  nVertExplored++;
4727  }
4728  }
4729 
4730  // Reset current queue and set to next queue
4731  currQueue.clear();
4732  currQueue.swap(nextQueue);
4733  }
4734  return (nBlocks);
4735 }
4736 
4737 int mesh::ConnectedVolumes(vector<int> &voluBlock, const vector<bool> &boundaryFaces) const
4738 {
4739  // Fills a vector with a number for each volume corresponding to a group of
4740  // connected edges it is part of , can be used close surfaces in 2D or
4741  // volumes in 3D. Uses a flood fill with queue method Boundary faces are
4742  // faces which stop the the flood exploring through them it is a boolean
4743 
4744  int nVoluExplored, nVolus, nSurfs, nBlocks, nCurr, nSurfsCurr, ii, jj, kk;
4745  vector<bool> volStatus; // 1 explored 0 not explored
4746 
4747  vector<int> currQueue, nextQueue; // Current and next queues of indices
4748  bool boundConstrAct = false;
4749  // Preparation of the arrays;
4750  nVolus = volus.size();
4751  nSurfs = surfs.size();
4752  nBlocks = 0;
4753  nVoluExplored = 0;
4754 
4755  volStatus.assign(nVolus, false);
4756 
4757  if (int(voluBlock.size()) == 0)
4758  {
4759  // Standard behaviour of grouping all connected volumes when voluBlock
4760  // is empty
4761  voluBlock.clear();
4762  voluBlock.assign(nVolus, 0);
4763  }
4764  else if (int(voluBlock.size()) == nVolus)
4765  {
4766  // Treat volumes with non zero value as already processed.
4767  // This allows these volumes to separate blocks of volumes.
4768  for (int i = 0; i < nVolus; ++i)
4769  {
4770  if (voluBlock[i] != 0)
4771  {
4772  volStatus[i] = true;
4773  nVoluExplored++;
4774  }
4775  }
4776  }
4777  else
4778  {
4779  // If voluBlock and nVolus are difference sizes the behaviour is
4780  // undefined.
4781  cerr << "Error in " << __PRETTY_FUNCTION__ << ": " << endl
4782  << "voluBlock should be empty or the size of mesh.volus";
4783  RSVS3D_ERROR_ARGUMENT("voluBlock vector incompatible with mesh.");
4784  }
4785  if (boundaryFaces.size() == 0)
4786  {
4787  boundConstrAct = false;
4788  }
4789  else if (int(boundaryFaces.size()) == nSurfs)
4790  {
4791  boundConstrAct = true;
4792  }
4793  else
4794  {
4795  cerr << "Error in " << __PRETTY_FUNCTION__ << ": " << endl
4796  << "boundaryFaces should be empty or the size of mesh.surfs";
4797  RSVS3D_ERROR_ARGUMENT("boundaryFaces vector incompatible with mesh.");
4798  }
4799  currQueue.reserve(nVolus / 2);
4800  nextQueue.reserve(nVolus / 2);
4801 
4802  // While Loop, while not all volumes explored
4803  while (nVoluExplored < nVolus)
4804  {
4805  // if currQueue is empty start new block
4806  if (currQueue.size() < 1)
4807  {
4808  ii = 0;
4809  while (ii < nVolus && volStatus[ii])
4810  {
4811  ii++;
4812  }
4813  if (volStatus[ii])
4814  {
4815  cerr << "Error starting point for loop not found despite"
4816  " max number of volume not reached"
4817  << endl;
4818  cerr << "Error in " << __PRETTY_FUNCTION__ << endl;
4819  RSVS3D_ERROR_RANGE(" : Starting point for block not found");
4820  }
4821  currQueue.push_back(ii);
4822  nBlocks++;
4823  }
4824  // Explore current queue
4825  nCurr = currQueue.size();
4826  for (ii = 0; ii < nCurr; ++ii)
4827  {
4828  if (volStatus[currQueue[ii]])
4829  {
4830  // Volume already explored
4831  continue;
4832  }
4833  voluBlock[currQueue[ii]] = nBlocks;
4834  nSurfsCurr = volus(currQueue[ii])->surfind.size();
4835  for (jj = 0; jj < nSurfsCurr; ++jj)
4836  {
4837  int sTempInd = surfs.find(volus(currQueue[ii])->surfind[jj]);
4838  if (boundConstrAct && boundaryFaces[sTempInd])
4839  {
4840  // If a boundary has been provided and this face is one
4841  continue;
4842  }
4843  kk = int(surfs(sTempInd)->voluind[0] == volus(currQueue[ii])->index);
4844  if (surfs(sTempInd)->voluind[kk] == 0)
4845  {
4846  // if volume index is 0 skip this
4847  continue;
4848  }
4849  nextQueue.push_back(volus.find(surfs(sTempInd)->voluind[kk]));
4850 #ifdef SAFE_ALGO
4851  if (volus.find(surfs(sTempInd)->voluind[kk]) == -1)
4852  {
4853  cerr << "Surf index: " << volus(currQueue[ii])->surfind[jj]
4854  << " volume index:" << surfs(sTempInd)->voluind[kk] << endl;
4855  cerr << "Surf connected to non existant volume" << endl;
4856  cerr << "Error in " << __PRETTY_FUNCTION__ << endl;
4857  RSVS3D_ERROR_RANGE(" : Volume not found");
4858  }
4859 #endif
4860  }
4861  volStatus[currQueue[ii]] = true;
4862  nVoluExplored++;
4863  }
4864 
4865  // Reset current queue and set to next queue
4866  currQueue.clear();
4867  currQueue.swap(nextQueue);
4868  }
4869  return (nBlocks);
4870 }
4871 
4872 coordvec mesh::CalcCentreVolu(int ind) const
4873 {
4874  // takes the position int
4875 
4876  coordvec ret;
4877  coordvec temp;
4878  double edgeLength;
4879  double voluLength;
4880  int ii, ni, jj, nj;
4881  int cSurf, a;
4882  voluLength = 0;
4883  a = volus.find(ind);
4884  ni = volus(a)->surfind.size();
4885  for (ii = 0; ii < ni; ++ii)
4886  {
4887  cSurf = surfs.find(volus(a)->surfind[ii]);
4888  nj = surfs(cSurf)->edgeind.size();
4889  for (jj = 0; jj < nj; ++jj)
4890  {
4891  temp.assign(0, 0, 0);
4892  temp.add(verts.isearch(edges.isearch(surfs(cSurf)->edgeind[jj])->vertind[0])->coord);
4893  temp.substract(verts.isearch(edges.isearch(surfs(cSurf)->edgeind[jj])->vertind[1])->coord);
4894 
4895  edgeLength = temp.CalcNorm();
4896  voluLength += edgeLength;
4897 
4898  temp.add(verts.isearch(edges.isearch(surfs(cSurf)->edgeind[jj])->vertind[1])->coord);
4899  temp.add(verts.isearch(edges.isearch(surfs(cSurf)->edgeind[jj])->vertind[1])->coord);
4900  temp.mult(edgeLength);
4901 
4902  ret.add(temp.usedata());
4903  }
4904  }
4905  ret.div(voluLength);
4906  return (ret);
4907 }
4908 
4909 coordvec mesh::CalcPseudoNormalSurf(int ind) const
4910 {
4911  coordvec ret;
4912  coordvec temp1, temp2, temp3;
4913  double edgeLength;
4914  double voluLength;
4915  vector<int> vertList;
4916  int jj, nj, cSurf;
4917 
4918  voluLength = 0;
4919  cSurf = surfs.find(ind);
4920  surfs(cSurf)->OrderedVerts(this, vertList);
4921 
4922  nj = vertList.size();
4923  ret.assign(0, 0, 0);
4924  for (jj = 0; jj < nj; ++jj)
4925  {
4926  temp1.assign(0, 0, 0);
4927  temp2.assign(0, 0, 0);
4928  temp1.add(verts.isearch(vertList[(jj + 1) % nj])->coord);
4929  temp2.add(verts.isearch(vertList[(jj + nj - 1) % nj])->coord);
4930  temp1.substract(verts.isearch(vertList[jj])->coord);
4931  temp2.substract(verts.isearch(vertList[jj])->coord);
4932 
4933  temp3 = temp1.cross(temp2.usedata());
4934 
4935  edgeLength = temp3.CalcNorm();
4936  voluLength += edgeLength;
4937 
4938  ret.add(temp3.usedata());
4939  }
4940 
4941  ret.div(voluLength);
4942  return (ret);
4943 }
4944 
4949 {
4950  if (this->WhatDim() == 3)
4951  {
4952  this->OrientSurfaceVolume();
4953  }
4954  else if (this->WhatDim() == 2)
4955  {
4956  this->OrientEdgeSurface();
4957  }
4958  else
4959  {
4960  // Could support higher dimensions
4961  }
4962 }
4963 
4964 void mesh::OrientEdgeSurface()
4965 {
4966  cerr << "Warning: not coded yet in " << __PRETTY_FUNCTION__ << endl;
4967 }
4968 
4969 void mesh::OrientSurfaceVolume()
4970 {
4971  // Orders the surf.voluind [c0 c1] such that the surface normal
4972  // vector points
4973  // from c0 to c1
4974  // This is done by using the surface normals and checking they go towards
4975  // the centre of the cell
4976 
4977  int nBlocks, ii, jj, ni, nj, kk;
4978  vector<int> surfOrient;
4979  vector<bool> isFlip;
4980  double dotProd;
4981  coordvec centreVolu, normalVec;
4982 
4983  nBlocks = OrientRelativeSurfaceVolume(surfOrient);
4984  isFlip.assign(nBlocks, false);
4985  //========================================
4986  // Select direction using coordinate geometry
4987  // use a surface
4988 
4989  for (ii = 1; ii <= nBlocks; ii++)
4990  {
4991  jj = -1;
4992  nj = surfOrient.size();
4993  do
4994  {
4995  jj++;
4996  while (jj < nj && ii != abs(surfOrient[jj]))
4997  {
4998  jj++;
4999  }
5000  if (jj == nj)
5001  { // if the orientation cannot be defined
5002  dotProd = 1.0;
5003  kk = 0;
5004  cerr << endl
5005  << "Warning: Cell orientations could not "
5006  "be computed ";
5007  cerr << " in " << __PRETTY_FUNCTION__;
5008  break;
5009  }
5010  kk = surfs(jj)->voluind[0] == 0;
5011  centreVolu = CalcCentreVolu(surfs(jj)->voluind[kk]);
5012  normalVec = CalcPseudoNormalSurf(surfs(jj)->index);
5013 
5014  centreVolu.substractfrom(verts.isearch(edges.isearch(surfs(jj)->edgeind[0])->vertind[0])->coord);
5015  dotProd = centreVolu.dot(normalVec.usedata());
5016  } while (!isfinite(dotProd) || (fabs(dotProd) < numeric_limits<double>::epsilon()));
5017 
5018  isFlip[ii - 1] = (((dotProd < 0.0) && (kk == 0)) || ((dotProd > 0.0) && (kk == 1)));
5019  }
5020  ni = surfOrient.size();
5021  for (ii = 0; ii < ni; ++ii)
5022  {
5023  if (isFlip[abs(surfOrient[ii]) - 1])
5024  {
5025  surfs.elems[ii].FlipVolus();
5026  }
5027  }
5028  this->facesAreOriented = true;
5029 }
5030 
5031 int mesh::OrientRelativeSurfaceVolume(vector<int> &surfOrient)
5032 {
5033  int nSurfExplored, nSurfs, nBlocks, nCurr, currEdge, testSurf, relOrient;
5034  int ii, jj, kk, nj, nk;
5035  vector<bool> surfStatus; // 1 explored 0 not explored
5036  vector<vector<int>> orderVert;
5037  bool isConnec, t0, t1, t3, t4, isFlip;
5038  // Current and next queues of indices
5039  vector<int> currQueue, nextQueue, emptVert;
5040 
5041  // Preparation of the arrays;
5042  nSurfs = surfs.size();
5043 
5044  surfStatus.assign(nSurfs, false);
5045  surfOrient.assign(nSurfs, 0);
5046  currQueue.reserve(nSurfs / 2); // list of positions
5047  nextQueue.reserve(nSurfs / 2);
5048  orderVert.reserve(nSurfs);
5049 
5050  // =======================================
5051  // Collect surface vertex lists
5052  emptVert.assign(6, 0);
5053  for (ii = 0; ii < nSurfs; ii++)
5054  {
5055  orderVert.push_back(emptVert);
5056  surfs(ii)->OrderedVerts(this, orderVert[ii]);
5057  }
5058 
5059  // ========================================
5060  // Flooding to find relative orientations of surfaces
5061  // Start from a surf that is in no list,
5062  // look at each its edges
5063  // find adjacent surfaces(checking they share a cell)
5064  // -> compute relative orientation (using idea of
5065  // contra-rotating adjacent surfs)
5066  // -> add surface to queue
5067  nBlocks = 0;
5068  nSurfExplored = 0;
5069  if (meshDim < 3)
5070  {
5071  return (nBlocks);
5072  }
5073  // cout << " " << nSurfs << " | " ;
5074  while (nSurfExplored < nSurfs)
5075  {
5076  // if currQueue is empty start new block
5077  // cout << " " << nSurfExplored ;
5078  if (currQueue.size() < 1)
5079  {
5080  ii = 0;
5081  while (ii < nSurfs && surfStatus[ii])
5082  {
5083  ii++;
5084  }
5085  if (ii == nSurfs)
5086  {
5087  // cout << " | " << nSurfs << " | " ;
5088  RSVS3D_ERROR_RANGE(" Start point not found");
5089  }
5090  // ii=nSurfs-1;
5091  // while(ii>=0 && surfStatus[ii])
5092  // { ii--; }
5093  // if (ii==-1){
5094  // //cout << " | " << nSurfs << " | " ;
5095  // RSVS3D_ERROR_RANGE(" Start point not found");
5096  // }
5097  currQueue.push_back(ii);
5098  nBlocks++;
5099  surfStatus[ii] = true;
5100  nSurfExplored++;
5101  surfOrient[ii] = nBlocks;
5102  }
5103  // Explore current queue
5104  nCurr = currQueue.size();
5105  for (ii = 0; ii < nCurr; ++ii)
5106  {
5107  nj = surfs(currQueue[ii])->edgeind.size();
5108  for (jj = 0; jj < nj; ++jj)
5109  {
5110  currEdge = edges.find(surfs(currQueue[ii])->edgeind[jj]);
5111  nk = edges(currEdge)->surfind.size();
5112  for (kk = 0; kk < nk; ++kk)
5113  {
5114  // tN -> volu[N] is shared
5115  testSurf = surfs.find(edges(currEdge)->surfind[kk]);
5116  t0 = (surfs(testSurf)->voluind[0] == surfs(currQueue[ii])->voluind[0] ||
5117  surfs(testSurf)->voluind[1] == surfs(currQueue[ii])->voluind[0]) &&
5118  (surfs(currQueue[ii])->voluind[0] != 0);
5119 
5120  t1 = (surfs(testSurf)->voluind[0] == surfs(currQueue[ii])->voluind[1] ||
5121  surfs(testSurf)->voluind[1] == surfs(currQueue[ii])->voluind[1]) &&
5122  (surfs(currQueue[ii])->voluind[1] != 0);
5123  // if either volume is shared surface is to be flooded
5124  isConnec = (edges(currEdge)->surfind[kk] != surfs(currQueue[ii])->index) && (t0 || t1) &&
5125  (!surfStatus[testSurf]);
5126 
5127  if (isConnec)
5128  {
5129  // Test rotation
5130  relOrient = OrderMatchLists(orderVert[currQueue[ii]], orderVert[testSurf],
5131  edges(currEdge)->vertind[0], edges(currEdge)->vertind[1]);
5132  // Add to the next queue
5133  nextQueue.push_back(testSurf);
5134  nSurfExplored++;
5135  surfStatus[testSurf] = true;
5136  surfOrient[testSurf] = -1 * relOrient * surfOrient[currQueue[ii]];
5137 
5138  // Flip volumes to match
5139  t3 = (surfs(testSurf)->voluind[0] == surfs(currQueue[ii])->voluind[0]);
5140  t4 = (surfs(testSurf)->voluind[1] == surfs(currQueue[ii])->voluind[1]);
5141  isFlip = ((relOrient == -1) && ((t0 && !t3) || (t1 && !t4))) ||
5142  ((relOrient == 1) && ((t0 && t3) || (t1 && t4)));
5143  if (isFlip)
5144  {
5145  surfs.elems[testSurf].FlipVolus();
5146  }
5147  }
5148  }
5149  }
5150  }
5151  // Reset current queue and set to next queue
5152  currQueue.clear();
5153  currQueue.swap(nextQueue);
5154  }
5155  return (nBlocks);
5156 }
5157 
5158 grid::transformation mesh::Scale()
5159 {
5160  grid::limits domain;
5161  for (int i = 0; i < 3; ++i)
5162  {
5163  domain[i] = {0.0, 1.0};
5164  }
5165  return this->Scale(domain);
5166 }
5167 
5168 grid::transformation mesh::Scale(const grid::limits &domain)
5169 {
5170  /*
5171  Scale the mesh to be in the range domain where domain is a 2D array:
5172  [
5173  x [lb ub]
5174  y [lb ub]
5175  z [lb ub]
5176  ]
5177  */
5178 
5179  // ``transformation`` stores for each dimension:
5180  // {new min, old min, multiplier}
5182  grid::limits currDomain = this->BoundingBox();
5183 
5184  // Calculate modification parameters
5185  for (int i = 0; i < 3; ++i)
5186  {
5187  transformation[i][0] = domain[i][0];
5188  transformation[i][1] = currDomain[i][0];
5189  transformation[i][2] = (domain[i][1] - domain[i][0]) / (currDomain[i][1] - currDomain[i][0]);
5190  // Handle flat domains by ignoring the dimension
5191  if (!isfinite(transformation[i][2]))
5192  {
5193  transformation[i][2] = 1.0;
5194  }
5195  }
5196 
5197  // Recalculate grid vertex positions
5198  this->LinearTransform(transformation);
5199  return transformation;
5200 }
5201 
5208 {
5209  int nVerts = int(this->verts.size());
5210 
5211  for (int ii = 0; ii < nVerts; ++ii)
5212  {
5213  for (int jj = 0; jj < 3; ++jj)
5214  {
5215  this->verts.elems[ii].coord[jj] =
5216  transform[jj][0] + ((this->verts(ii)->coord[jj] - transform[jj][1]) * transform[jj][2]);
5217  }
5218  }
5219 }
5226 {
5227  this->_LinearTransformGeneration(transform, &meshdependence::parentmesh);
5228  this->_LinearTransformGeneration(transform, &meshdependence::childmesh);
5229 }
5230 
5238 void mesh::_LinearTransformGeneration(const grid::transformation &transform, vector<mesh *> meshdependence::*mp)
5239 {
5240  for (mesh *famMember : this->meshtree.*mp)
5241  {
5242  famMember->LinearTransform(transform);
5243  famMember->_LinearTransformGeneration(transform, mp);
5244  }
5245 }
5246 
5247 grid::limits mesh::BoundingBox() const
5248 {
5249  int nVerts = this->verts.size();
5250  grid::limits currDomain;
5251  for (int i = 0; i < 3; ++i)
5252  {
5253  currDomain[i] = {std::numeric_limits<double>::infinity(), -std::numeric_limits<double>::infinity()};
5254  }
5255  for (int ii = 0; ii < nVerts; ++ii)
5256  {
5257  for (int jj = 0; jj < 3; ++jj)
5258  {
5259  currDomain[jj][0] =
5260  currDomain[jj][0] <= this->verts(ii)->coord[jj] ? currDomain[jj][0] : this->verts(ii)->coord[jj];
5261  currDomain[jj][1] =
5262  currDomain[jj][1] >= this->verts(ii)->coord[jj] ? currDomain[jj][1] : this->verts(ii)->coord[jj];
5263  }
5264  }
5265  return (currDomain);
5266 }
5267 
5268 void mesh::ReturnBoundingBox(std::array<double, 3> &lowerB, std::array<double, 3> &upperB) const
5269 {
5270  grid::limits currDomain = this->BoundingBox();
5271  for (int i = 0; i < 3; ++i)
5272  {
5273  lowerB[i] = currDomain[i][0];
5274  upperB[i] = currDomain[i][1];
5275  }
5276 }
5277 
5278 void mesh::LoadTargetFill(const std::string &fileName)
5279 {
5280  vector<double> fillVals;
5281  double ft;
5282  int nElms, count;
5283  ifstream file;
5284 
5285  file.open(fileName);
5286  CheckFStream(file, __PRETTY_FUNCTION__, fileName);
5287  nElms = 0;
5288  if (this->WhatDim() == 3)
5289  {
5290  nElms = this->volus.size();
5291  }
5292  else if (this->WhatDim() == 2)
5293  {
5294  nElms = this->surfs.size();
5295  }
5296  else
5297  {
5298  RSVS3D_ERROR_ARGUMENT("Dimensionality of the target not supported.");
5299  }
5300 
5301  fillVals.reserve(nElms);
5302  count = 0;
5303  while (!file.eof() && count < nElms)
5304  {
5305  file >> ft;
5306  fillVals.push_back(ft);
5307  ++count;
5308  }
5309  cout << "fill loaded : ";
5310  DisplayVector(fillVals);
5311  cout << endl;
5312  if (this->WhatDim() == 3)
5313  {
5314  for (int i = 0; i < nElms; ++i)
5315  {
5316  this->volus[i].target = fillVals[i % count];
5317  }
5318  }
5319  else if (this->WhatDim() == 2)
5320  {
5321  for (int i = 0; i < nElms; ++i)
5322  {
5323  this->surfs[i].target = fillVals[i % count];
5324  }
5325  }
5326  this->PrepareForUse();
5327 }
5328 
5357 std::vector<int> mesh::AddBoundary(const std::vector<double> &lb, const std::vector<double> &ub)
5358 {
5359  /*
5360  Adds elements on a boundary defined by upper bounds and lower bounds.
5361 
5362  THis method could be readily refactored to allow treatment of more
5363  complex boundaries
5364 
5365  Steps:
5366  1 - Identify vertices lying outside
5367  2 - Indentify connectors lying on boundary
5368  a - edges
5369  b - surfs
5370  c - volus
5371  3 - Introduce boundary vertices (BV)
5372  4 - Connect those BV to form new boundary edges (BE)
5373  5 - Assemble BEs inside a volu into a boundary surf (BS)
5374  (This process is similar to the voronoisation)
5375 
5376  Args:
5377  lb : lower bounds in vector form.
5378  up : upper bounds in vector form.
5379 
5380  Returns:
5381  A list of vertex indices which lie outside the boundary.
5382  */
5383  mesh meshAdd;
5384  std::vector<int> vertOutInd; // return
5385 #ifdef SAFE_ALGO
5386  bool flagErr1, flagErr2;
5387 #endif
5388  std::vector<bool> vertOut;
5389  std::vector<bool> edgeOut;
5390  std::vector<int> edgeBound;
5391  std::vector<bool> surfOut;
5392  std::vector<int> surfBound;
5393  std::vector<bool> voluOut;
5394  std::vector<int> voluBound;
5395 
5396  int vertSize, edgeSize, edgeSize2, surfSize, surfSize2, voluSize, voluSize2, count, countPrev;
5397 
5398  vertSize = this->verts.size();
5399  edgeSize = this->edges.size();
5400  surfSize = this->surfs.size();
5401  voluSize = this->volus.size();
5402  vertOut.assign(vertSize, false);
5403  edgeBound.reserve(edgeSize);
5404  surfBound.reserve(surfSize);
5405  voluBound.reserve(voluSize);
5406 
5407  meshAdd.Init(0, 0, 0, 0);
5408 
5409  // Mark outer vertices
5410  for (int i = 0; i < vertSize; ++i)
5411  {
5412  for (int j = 0; j < 3; ++j)
5413  {
5414  if (this->verts(i)->coord[j] > ub[j] || this->verts(i)->coord[j] < lb[j])
5415  {
5416  vertOut[i] = true;
5417  break;
5418  }
5419  }
5420  }
5421  for (int i = 0; i < edgeSize; ++i)
5422  { // for each edge if it's vertices are one in one out.
5423  if (vertOut[this->verts.find(this->edges(i)->vertind[0])] ^
5424  vertOut[this->verts.find(this->edges(i)->vertind[1])])
5425  {
5426  edgeBound.push_back(this->edges(i)->index);
5427  }
5428  }
5429  count = edgeBound.size();
5430  auto tempVec = this->edges.find_list(edgeBound);
5431  surfBound = ConcatenateVectorField(this->edges, &edge::surfind, tempVec);
5432  sort(surfBound);
5433  unique(surfBound);
5434  tempVec.clear();
5435  tempVec = this->surfs.find_list(surfBound);
5436  voluBound = ConcatenateVectorField(this->surfs, &surf::voluind, tempVec);
5437  sort(voluBound);
5438  unique(voluBound);
5439  if (voluBound.size() && voluBound[0] == 0)
5440  {
5441  voluBound[0] = voluBound.back();
5442  voluBound.pop_back();
5443  }
5444  // Create all the mesh containers for the new mesh parts
5445  meshAdd.Init(edgeBound.size(), edgeBound.size() + surfBound.size(), surfBound.size() + voluBound.size(),
5446  voluBound.size());
5447 #ifdef RSVS_VERBOSE
5448  this->displight();
5449 #endif // RSVS_VERBOSE
5450  meshAdd.PopulateIndices();
5451  this->MakeCompatible_inplace(meshAdd);
5452  // meshAdd.disp();
5453  this->Concatenate(meshAdd);
5454  this->HashArray();
5455 #ifdef RSVS_VERBOSE
5456  this->displight();
5457 #endif // RSVS_VERBOSE
5458 
5459  // Handle edges:
5460  // 1 - Double the edge.
5461  // 2 - Add the vertex
5462  // 3 - Connect the vertex
5463  // 4 - Assign edges as internal or external
5464  count = edgeBound.size();
5465  tempVec = this->edges.find_list(edgeBound);
5466  for (int i = 0; i < count; ++i)
5467  {
5468  // Replicate edge (changing index)
5469  auto tempInd = this->edges[i + edgeSize].index;
5470  this->edges[i + edgeSize] = this->edges[tempVec[i]];
5471  this->edges[i + edgeSize].index = tempInd;
5472  for (auto temp : this->surfs.find_list(this->edges[i + edgeSize].surfind))
5473  {
5474  this->surfs[temp].edgeind.push_back(tempInd);
5475  }
5476  // Compute vertex position
5477  int iIn = 0, iOut = 0, subIn, subOut;
5478  iOut += !vertOut[this->verts.find(this->edges[tempVec[i]].vertind[0])];
5479  iIn += vertOut[this->verts.find(this->edges[tempVec[i]].vertind[0])];
5480 #ifdef SAFE_ALGO
5481  if (!(vertOut[this->verts.find(this->edges[tempVec[i]].vertind[0])] ^
5482  vertOut[this->verts.find(this->edges[tempVec[i]].vertind[1])]))
5483  {
5484  RSVS3D_ERROR_LOGIC("Edge Should be connected to one inner and"
5485  " one outer vertex, this is not the case.");
5486  }
5487  flagErr1 = vertOut[this->verts.find(this->edges[tempVec[i]].vertind[iIn])];
5488  flagErr2 = !vertOut[this->verts.find(this->edges[tempVec[i]].vertind[iOut])];
5489  if (flagErr1 && flagErr2)
5490  {
5491  RSVS3D_ERROR_LOGIC("Coord In is Out and Coord out is in");
5492  }
5493  else if (flagErr1)
5494  {
5495  RSVS3D_ERROR_LOGIC("Coord In is Out");
5496  }
5497  else if (flagErr2)
5498  {
5499  RSVS3D_ERROR_LOGIC("Coord out is in");
5500  }
5501 #endif // SAFE_ALGO
5502  subIn = this->verts.find(this->edges[tempVec[i]].vertind[iIn]);
5503  subOut = this->verts.find(this->edges[tempVec[i]].vertind[iOut]);
5504  meshhelp::PlaceBorderVertex(this->verts[subIn].coord, this->verts[subOut].coord, lb, ub,
5505  this->verts[i + vertSize].coord);
5506 
5507  int count2 = this->verts[subOut].edgeind.size();
5508  for (int j = 0; j < count2; ++j)
5509  {
5510  if (this->verts[subOut].edgeind[j] == this->edges[tempVec[i]].index)
5511  {
5512  this->verts[subOut].edgeind[j] = this->edges[i + edgeSize].index;
5513  }
5514  }
5515 
5516  this->edges[i + edgeSize].vertind[iIn] = this->verts[i + vertSize].index;
5517  this->edges[tempVec[i]].vertind[iOut] = this->verts[i + vertSize].index;
5518  this->verts[i + vertSize].edgeind.push_back(this->edges[tempVec[i]].index);
5519  this->verts[i + vertSize].edgeind.push_back(this->edges[i + edgeSize].index);
5520  vertOut.push_back(false); // Add new vertex as an inside vertex
5521  this->ArraysAreHashed();
5522  }
5523  this->verts.HashArray();
5524  this->edges.HashArray();
5525  edgeSize2 = edgeSize + count;
5526  edgeOut.assign(edgeSize2, false);
5527  for (int i = 0; i < edgeSize2; ++i)
5528  { // assigns an edge as outside if either of it's vertices are out
5529  edgeOut[i] = vertOut[this->verts.find(this->edges(i)->vertind[0])] ||
5530  vertOut[this->verts.find(this->edges(i)->vertind[1])];
5531  }
5532  // Handle surfaces
5533  // 1 - double the surface
5534  // 2 - add the new edge
5535  // 3 - close the two surfaces
5536  // Need to handle multiple cuts in the same surface
5537  countPrev = 0;
5538  do
5539  {
5540  count = surfBound.size();
5541  tempVec.clear();
5542  tempVec = this->surfs.find_list(surfBound);
5543  //===============================================
5544  for (int i = countPrev; i < count; ++i)
5545  {
5546  // Replicate surf (changing index)
5547  auto tempInd = this->surfs[i + surfSize].index;
5548  this->surfs[i + surfSize] = this->surfs[tempVec[i]];
5549  this->surfs[i + surfSize].index = tempInd;
5550 
5551  meshhelp::SplitBorderSurfaceEdgeind(*this, edgeOut, this->surfs[tempVec[i]].edgeind,
5552  this->surfs[i + surfSize].edgeind);
5553 
5554  // Find the vertind connectivity of the new edge.
5555  this->edges[edgeSize2 + i].vertind = meshhelp::FindVertInFromEdgeOut(
5556  *this, vertOut, this->surfs(i + surfSize)->edgeind, this->surfs(tempVec[i])->edgeind);
5557 
5558  if (this->edges[edgeSize2 + i].vertind.size() > 2)
5559  {
5560  this->ArraysAreHashed();
5561  meshhelp::HandleMultiSurfaceSplit(*this, this->surfs.elems[tempVec[i]].edgeind,
5562  this->surfs.elems[surfSize + i].edgeind,
5563  this->edges.elems[edgeSize2 + i].vertind);
5564  surfBound.push_back(this->surfs(tempVec[i])->index);
5565  }
5566  // Switch the edge connectivity of certain edges in scoped mode
5567  this->ArraysAreHashed();
5568  this->SwitchIndex(6, this->surfs(tempVec[i])->index, this->surfs(i + surfSize)->index,
5569  this->surfs(i + surfSize)->edgeind);
5570  // assign new edge.surfind and surf.edgeind connectivity
5571  this->edges[edgeSize2 + i].surfind.push_back(this->surfs[i + surfSize].index);
5572  this->edges[edgeSize2 + i].surfind.push_back(this->surfs[tempVec[i]].index);
5573  this->surfs[i + surfSize].edgeind.push_back(this->edges[edgeSize2 + i].index);
5574  this->surfs[tempVec[i]].edgeind.push_back(this->edges[edgeSize2 + i].index);
5575  // Assign the vertices edgeind connectivity
5576  int count2 = this->edges[edgeSize2 + i].vertind.size();
5577  for (int j = 0; j < count2; ++j)
5578  {
5579  this->verts.elems[this->verts.find(this->edges[edgeSize2 + i].vertind[j])].edgeind.push_back(
5580  this->edges[edgeSize2 + i].index);
5581  }
5582  edgeOut.push_back(false); // New edge is inside
5583  this->ArraysAreHashed();
5584  }
5585  //===============================================
5586  // if surfBound has grown surfaces require cutting more than once.
5587  countPrev = count;
5588  count = surfBound.size();
5589  if (count != countPrev)
5590  {
5591  meshAdd.Init(0, count - countPrev, count - countPrev, 0);
5592  meshAdd.PopulateIndices();
5593  this->SetMaxIndex();
5594  meshAdd.SetMaxIndex();
5595  this->MakeCompatible_inplace(meshAdd);
5596  this->Concatenate(meshAdd);
5597  this->HashArray();
5598  }
5599  } while (count != countPrev);
5600  this->verts.HashArray();
5601  this->edges.HashArray();
5602  this->surfs.HashArray();
5603  surfSize2 = surfSize + count;
5604  surfOut.assign(surfSize2, false);
5605  for (int i = 0; i < surfSize2; ++i)
5606  { // assigns a surf as outside if any of it's edges are out
5607  int count2 = this->surfs(i)->edgeind.size();
5608  for (int j = 0; j < count2; ++j)
5609  {
5610  surfOut[i] = surfOut[i] || edgeOut[this->edges.find(this->surfs(i)->edgeind[j])];
5611  }
5612  }
5613  // Handle Volumes
5614  // 1 - Double the volume
5615  // 2 - Add the new surface
5616  // 3 - Close the two volumes
5617  count = voluBound.size();
5618  tempVec.clear();
5619  tempVec = this->volus.find_list(voluBound);
5620  for (int i = 0; i < count; ++i)
5621  {
5622  // Replicate volu (changing index)
5623  auto tempInd = this->volus[i + voluSize].index;
5624  this->volus[i + voluSize] = this->volus[tempVec[i]];
5625  this->volus[i + voluSize].index = tempInd;
5626 
5627  // Split surfind connectivity
5628  meshhelp::SplitBorderVolumeSurfind(*this, surfOut, this->volus[tempVec[i]].surfind,
5629  this->volus[i + voluSize].surfind);
5630  // Switch the volumes connectivity of certain surfaces in scoped mode
5631  this->ArraysAreHashed();
5632  this->SwitchIndex(7, this->volus(tempVec[i])->index, this->volus(i + voluSize)->index,
5633  this->volus(i + voluSize)->surfind);
5634  // ^ triggers a warning which will need to be suppressed
5635  // Find the edgeind connectivity of the new surf.
5636  this->surfs[surfSize2 + i].edgeind =
5637  meshhelp::FindEdgeInFromSurfOut(*this, edgeOut, this->volus(i + voluSize)->surfind);
5638  // Connect the new surface to the two volumes which were split
5639  this->surfs[surfSize2 + i].voluind[0] = this->volus[i + voluSize].index;
5640  this->surfs[surfSize2 + i].voluind[1] = this->volus[tempVec[i]].index;
5641  this->volus[tempVec[i]].surfind.push_back(this->surfs[surfSize2 + i].index);
5642  this->volus[i + voluSize].surfind.push_back(this->surfs[surfSize2 + i].index);
5643  // Assign the edges surfind connectivity
5644  int count2 = this->surfs(surfSize2 + i)->edgeind.size();
5645  this->ArraysAreHashed();
5646  for (int j = 0; j < count2; ++j)
5647  {
5648  this->edges.elems[this->edges.find(this->surfs[surfSize2 + i].edgeind[j])].surfind.push_back(
5649  this->surfs[surfSize2 + i].index);
5650  }
5651  surfOut.push_back(false); // New edge is inside
5652  this->ArraysAreHashed();
5653  }
5654  this->HashArray();
5655  voluSize2 = voluSize + count;
5656  voluOut.assign(voluSize2, false);
5657  for (int i = 0; i < voluSize2; ++i)
5658  { // assigns a surf as outside if any of it's surfs are out
5659  for (auto temp : this->volus(i)->surfind)
5660  {
5661  voluOut[i] = voluOut[i] || surfOut[this->surfs.find(temp)];
5662  }
5663  }
5664  this->HashArray();
5665  this->TightenConnectivity();
5666  this->TestConnectivityBiDir(__PRETTY_FUNCTION__);
5667  this->PrepareForUse();
5668  vertOutInd.reserve(this->verts.size());
5669  count = this->verts.size();
5670  for (int i = 0; i < count; ++i)
5671  {
5672  if (vertOut[i])
5673  {
5674  vertOutInd.push_back(this->verts(i)->index);
5675  }
5676  }
5677 
5678  return (vertOutInd);
5679 }
5680 
5681 void mesh::Crop(vector<int> indList, int indType)
5682 {
5683  /*
5684  Crops a mesh removing all the elements described by indlist.
5685 
5686  The cropping process is such that it leaves a functional mesh at the end.
5687  This process is performed in two cycles: one upward removing the elements
5688  of higher dimensionality connected to the identified objects. Then the
5689  process goes downwards removing all the orphan elements which have been
5690  created during the cleanup.
5691 
5692  Args:
5693  indList : List of indices of a given element type that need to
5694  be removed.
5695  indType : Type of the indices provided in the list. Default is 1
5696  which corresponds to vertices. vertex (indType=1), edge (2),
5697  surf (3), volu (4)
5698 
5699  Raises:
5700  invalid_argument : if the `indType` is not between 1 and 4.
5701 
5702  */
5703 
5704  // Check validity of input
5705  if (indType > 4 || indType < 1)
5706  {
5707  RSVS3D_ERROR_ARGUMENT("Type of index not recognised: \n"
5708  " vertex (indType=1), edge (2), surf (3), volu (4)");
5709  }
5710 
5711  std::vector<int> vertDel, edgeDel, surfDel, voluDel;
5712 
5713  int i = 1;
5714  if (indType == i++)
5715  {
5716  vertDel = indList;
5717  }
5718  else if (indType == i++)
5719  {
5720  edgeDel = indList;
5721  }
5722  else if (indType == i++)
5723  {
5724  surfDel = indList;
5725  }
5726  else if (indType == i++)
5727  {
5728  voluDel = indList;
5729  }
5730 
5731  switch (indType)
5732  {
5733  case 1: {
5734  auto vertSub = this->verts.find_list(vertDel);
5735  edgeDel = ConcatenateVectorField(this->verts, &vert::edgeind, vertSub);
5736  [[gnu::fallthrough]];
5737  }
5738  case 2: {
5739  auto edgeSub = this->edges.find_list(edgeDel);
5740  surfDel = ConcatenateVectorField(this->edges, &edge::surfind, edgeSub);
5741  [[gnu::fallthrough]];
5742  }
5743  case 3: {
5744  auto surfSub = this->surfs.find_list(surfDel);
5745  voluDel = ConcatenateVectorField(this->surfs, &surf::voluind, surfSub);
5746  }
5747  }
5748  // Remove indices from connectivity and propagate downwards
5749  // from the volumes.
5750  // Remove volumes
5751  sort(voluDel);
5752  unique(voluDel);
5753  int count = voluDel.size();
5754  if (count > 0)
5755  {
5756  if (voluDel[0] == 0)
5757  {
5758  voluDel.erase(voluDel.begin());
5759  }
5760  count--;
5761  for (int i = 0; i < count; ++i)
5762  {
5763  this->RemoveIndex(4, voluDel[i]);
5764  }
5765  }
5766  // Expand surf removal list
5767  count = this->surfs.size();
5768  for (int i = 0; i < count; ++i)
5769  {
5770  if (this->surfs(i)->voluind.size() == 0)
5771  {
5772  surfDel.push_back(this->surfs(i)->index);
5773  }
5774  else if (this->surfs(i)->voluind.size() == 1)
5775  {
5776  this->surfs[i].voluind.push_back(0);
5777  }
5778  }
5779  this->ArraysAreHashed();
5780  sort(surfDel);
5781  unique(surfDel);
5782  count = surfDel.size();
5783  for (int i = 0; i < count; ++i)
5784  {
5785  this->RemoveIndex(3, surfDel[i]);
5786  }
5787 
5788  count = this->edges.size();
5789  for (int i = 0; i < count; ++i)
5790  {
5791  if (this->edges(i)->surfind.size() == 0)
5792  {
5793  edgeDel.push_back(this->edges(i)->index);
5794  }
5795  }
5796  sort(edgeDel);
5797  unique(edgeDel);
5798  count = edgeDel.size();
5799  for (int i = 0; i < count; ++i)
5800  {
5801  this->RemoveIndex(2, edgeDel[i]);
5802  }
5803 
5804  count = this->verts.size();
5805  for (int i = 0; i < count; ++i)
5806  {
5807  if (this->verts(i)->edgeind.size() == 0)
5808  {
5809  vertDel.push_back(this->verts(i)->index);
5810  }
5811  }
5812  sort(vertDel);
5813  unique(vertDel);
5814  count = vertDel.size();
5815  for (int i = 0; i < count; ++i)
5816  {
5817  this->RemoveIndex(1, vertDel[i]);
5818  }
5819 
5820  this->verts.remove(vertDel);
5821  this->edges.remove(edgeDel);
5822  this->surfs.remove(surfDel);
5823  this->volus.remove(voluDel);
5824 
5825  this->PrepareForUse();
5826  this->RemoveSingularConnectors();
5827  this->PrepareForUse();
5828 }
5829 
5830 void mesh::CropAtBoundary(const vector<double> &lb, const vector<double> &ub)
5831 {
5832  /*
5833  Crops a mesh along a specified lower bound and upper bound.
5834 
5835  This function uses `mesh::AddBoundary` and `mesh::Crop` to perform this
5836  action.
5837  */
5838  auto vecDel = this->AddBoundary(lb, ub);
5839  this->Crop(vecDel, 1);
5840 }
5841 
5842 int mesh::EdgeFromVerts(int v1, int v2) const
5843 {
5844  int vExp = this->verts.isearch(v1)->edgeind.size() < this->verts.isearch(v2)->edgeind.size() ? v1 : v2;
5845  auto &el = this->verts.isearch(vExp)->edgeind;
5846 
5847  int retEdge = rsvs3d::constants::__notfound;
5848 
5849  for (auto e : el)
5850  {
5851  auto &vinds = this->edges.isearch(e)->vertind;
5852  if ((vinds[0] == v1 && vinds[1] == v2) || (vinds[1] == v1 && vinds[0] == v2))
5853  {
5854  retEdge = e;
5855  break;
5856  }
5857  }
5858 
5859  return retEdge;
5860 }
5861 
5872 int mesh::SurfFromEdges(int e1, int e2, int repetitionBehaviour) const
5873 {
5874  bool e1Smaller = this->edges.isearch(e1)->surfind.size() < this->edges.isearch(e2)->surfind.size();
5875  int eExp = e1Smaller ? e1 : e2;
5876  int eNoExp = !e1Smaller ? e1 : e2;
5877  auto &sl = this->edges.isearch(eExp)->surfind;
5878 
5879  int retSurf = rsvs3d::constants::__notfound;
5880  bool prevFind = false;
5881  for (auto s : sl)
5882  {
5883  auto &einds = this->surfs.isearch(s)->edgeind;
5884  for (auto e : einds)
5885  {
5886  if (e == eNoExp)
5887  {
5888  if (prevFind)
5889  { // if a repetition is detected
5890  if (repetitionBehaviour == 1)
5891  {
5892  return rsvs3d::constants::__notfound;
5893  }
5894  else
5895  {
5896  stringstream errstr;
5897  errstr << "Two or more surfaces connect edges e1 (" << e1 << ") and e2 (" << e2 << ")";
5898  RSVS3D_ERROR(errstr.str().c_str());
5899  }
5900  }
5901  retSurf = s;
5902  prevFind = true;
5903  if (repetitionBehaviour == 0)
5904  { // No check for repetition
5905  return retSurf;
5906  }
5907  else
5908  {
5909  break;
5910  }
5911  }
5912  }
5913  }
5914 
5915  return retSurf;
5916 }
5917 
5926 int mesh::VertFromVertEdge(int v, int e) const
5927 {
5928  auto &edgeVerts = this->edges.isearch(e)->vertind;
5929 
5930  return edgeVerts[int(edgeVerts[0] == v)];
5931 }
5932 void mesh::VerticesVector(int v1, int v2, coordvec &vec) const
5933 {
5934  vec = this->verts.isearch(v2)->coord;
5935  vec.substract(this->verts.isearch(v1)->coord);
5936 }
5937 void mesh::EdgeVector(int edgeIndex, coordvec &vec) const
5938 {
5939  auto e = this->edges.isearch(edgeIndex);
5940  int smallV = int(e->vertind[0] > e->vertind[1]);
5941  this->VerticesVector(e->vertind[smallV], e->vertind[abs(smallV - 1)], vec);
5942 }
5943 
5944 int mesh::OrderVertexEdges(int vertIndex)
5945 {
5946  return this->verts.elems[this->verts.find(vertIndex)].OrderEdges(this);
5947 }
5948 
5949 void mesh::ReOrder()
5950 {
5951  // Bind comparison functions into lambdas
5952  auto compareVerts = [&](const vert &i1, const vert &i2) -> bool { return (this->CompareVerts(i1, i2)); };
5953  auto compareEdges = [&](const edge &i1, const edge &i2) -> bool { return (this->CompareEdges(i1, i2)); };
5954  auto compareSurfs = [&](const surf &i1, const surf &i2) -> bool { return (this->CompareSurfs(i1, i2)); };
5955  auto compareVolus = [&](const volu &i1, const volu &i2) -> bool { return (this->CompareVolus(i1, i2)); };
5956 
5957  // Reorder the arrays according to element values
5958  sort(this->verts.elems.begin(), this->verts.elems.end(), compareVerts);
5959  this->verts.HashArray();
5960  sort(this->edges.elems.begin(), this->edges.elems.end(), compareEdges);
5961  this->edges.HashArray();
5962  sort(this->surfs.elems.begin(), this->surfs.elems.end(), compareSurfs);
5963  this->surfs.HashArray();
5964  sort(this->volus.elems.begin(), this->volus.elems.end(), compareVolus);
5965  this->volus.HashArray();
5966 
5967  this->HashArray();
5968 
5969  // Renumber elements according to position
5970  // Update connectivity first
5971  // Vertices
5972  int nVerts = this->verts.size();
5973  for (int i = 0; i < nVerts; ++i)
5974  {
5975  for (auto &ei : this->verts[i].edgeind)
5976  {
5977  ei = this->edges.find(ei, true) + 1;
5978  }
5979  }
5980 
5981  // Edges
5982  int nEdges = this->edges.size();
5983  for (int i = 0; i < nEdges; ++i)
5984  {
5985  for (auto &ei : this->edges[i].surfind)
5986  {
5987  ei = this->surfs.find(ei, true) + 1;
5988  }
5989  for (auto &ei : this->edges[i].vertind)
5990  {
5991  ei = this->verts.find(ei, true) + 1;
5992  }
5993  }
5994 
5995  // Surfs
5996  int nSurfs = this->surfs.size();
5997  for (int i = 0; i < nSurfs; ++i)
5998  {
5999  for (auto &ei : this->surfs[i].voluind)
6000  {
6001  ei = this->volus.find(ei, true) + 1;
6002  }
6003  for (auto &ei : this->surfs[i].edgeind)
6004  {
6005  ei = this->edges.find(ei, true) + 1;
6006  }
6007  }
6008 
6009  // Volumes
6010  int nVolus = this->volus.size();
6011  for (int i = 0; i < nVolus; ++i)
6012  {
6013  this->volus[i].index = i + 1;
6014  for (auto &ei : this->volus[i].surfind)
6015  {
6016  ei = this->surfs.find(ei, true) + 1;
6017  }
6018  }
6019 
6020  // Update indices
6021  nVerts = this->verts.size();
6022  for (int i = 0; i < nVerts; ++i)
6023  {
6024  this->verts[i].index = i + 1;
6025  }
6026 
6027  nEdges = this->edges.size();
6028  for (int i = 0; i < nEdges; ++i)
6029  {
6030  this->edges[i].index = i + 1;
6031  }
6032 
6033  nSurfs = this->surfs.size();
6034  for (int i = 0; i < nSurfs; ++i)
6035  {
6036  this->surfs[i].index = i + 1;
6037  }
6038 
6039  nVolus = this->volus.size();
6040  for (int i = 0; i < nVolus; ++i)
6041  {
6042  this->volus[i].index = i + 1;
6043  }
6044 
6045  // Finish
6046  this->PrepareForUse();
6047 #ifdef SAFE_ALGO
6048  this->TestConnectivityBiDir();
6049 #endif // SAFE_ALGO
6050 }
6051 
6052 std::pair<int, int> OrderMatchLists(const vector<int> &vec1, int p1, int p2)
6053 {
6054  int ord1 = 0;
6055  int kk = 0;
6056  int n = vec1.size();
6057  for (int ii = 0; ii < n; ++ii)
6058  {
6059  if (vec1[ii] == p1)
6060  {
6061  ord1 += ii;
6062  kk++;
6063  }
6064  else if (vec1[ii] == p2)
6065  {
6066  ord1 += -ii;
6067  kk++;
6068  }
6069  }
6070  if (ord1 > 1)
6071  {
6072  ord1 = -1;
6073  }
6074  if (ord1 < -1)
6075  {
6076  ord1 = 1;
6077  }
6078  return {ord1, kk};
6079 }
6080 
6081 int OrderMatchLists_old(const vector<int> &vec1, const vector<int> &vec2, int p1, int p2)
6082 {
6083  // compares the list vec1 and vec2 returning
6084  // 1 if indices p1 and p2 appear in the same order
6085  // -1 if indices p1 and p2 appear in opposite orders
6086  int ii, n, ord1, ord2, retVal, kk;
6087 
6088  ord1 = 0;
6089  kk = 0;
6090  n = vec1.size();
6091  for (ii = 0; ii < n; ++ii)
6092  {
6093  if (vec1[ii] == p1)
6094  {
6095  ord1 += ii;
6096  kk++;
6097  }
6098  else if (vec1[ii] == p2)
6099  {
6100  ord1 += -ii;
6101  kk++;
6102  }
6103  }
6104  if (ord1 > 1)
6105  {
6106  ord1 = -1;
6107  }
6108  if (ord1 < -1)
6109  {
6110  ord1 = 1;
6111  }
6112  if (kk != 2)
6113  {
6114  cerr << endl;
6115  DisplayVector(vec1);
6116  DisplayVector(vec2);
6117  cerr << endl << "p " << p1 << "," << p2 << endl;
6118  cerr << "Error : indices were not found in lists " << endl;
6119  cerr << " p1 and/or p2 did not appear in vec " << endl;
6120  cerr << " in " << __PRETTY_FUNCTION__ << endl;
6121  RSVS3D_ERROR_ARGUMENT("Incompatible list and index");
6122  }
6123 
6124  ord2 = 0;
6125  kk = 0;
6126  n = vec2.size();
6127  for (ii = 0; ii < n; ++ii)
6128  {
6129  if (vec2[ii] == p1)
6130  {
6131  ord2 += ii;
6132  kk++;
6133  }
6134  else if (vec2[ii] == p2)
6135  {
6136  ord2 += -ii;
6137  kk++;
6138  }
6139  }
6140  if (ord2 > 1)
6141  {
6142  ord2 = -1;
6143  }
6144  if (ord2 < -1)
6145  {
6146  ord2 = 1;
6147  }
6148  if (kk != 2)
6149  {
6150  cerr << endl;
6151  DisplayVector(vec1);
6152  DisplayVector(vec2);
6153  cerr << endl << "p " << p1 << "," << p2 << endl;
6154  cerr << "Error : indices were not found in lists " << endl;
6155  cerr << " p1 and/or p2 did not appear in vec " << endl;
6156  cerr << " in " << __PRETTY_FUNCTION__ << endl;
6157  RSVS3D_ERROR_ARGUMENT("Incompatible list and index");
6158  }
6159 
6160  retVal = (ord1 == ord2) * 2 - 1;
6161 
6162  return (retVal);
6163 }
6164 
6165 int OrderMatchLists(const vector<int> &vec1, const vector<int> &vec2, int p1, int p2)
6166 {
6167  // compares the list vec1 and vec2 returning
6168  // 1 if indices p1 and p2 appear in the same order
6169  // -1 if indices p1 and p2 appear in opposite orders
6170  int ord1, ord2, retVal, kk;
6171 
6172  auto pair1 = OrderMatchLists(vec1, p1, p2);
6173  ord1 = pair1.first;
6174  kk = pair1.second;
6175  if (kk != 2)
6176  {
6177  cerr << endl;
6178  DisplayVector(vec1);
6179  DisplayVector(vec2);
6180  cerr << endl << "p " << p1 << "," << p2 << endl;
6181  cerr << "Error : indices were not found in lists " << endl;
6182  cerr << " p1 and/or p2 did not appear in vec " << endl;
6183  cerr << " in " << __PRETTY_FUNCTION__ << endl;
6184  RSVS3D_ERROR_ARGUMENT("Incompatible list and index");
6185  }
6186 
6187  auto pair2 = OrderMatchLists(vec2, p1, p2);
6188  ord2 = pair2.first;
6189  kk = pair2.second;
6190  if (kk != 2)
6191  {
6192  cerr << endl;
6193  DisplayVector(vec1);
6194  DisplayVector(vec2);
6195  cerr << endl << "p " << p1 << "," << p2 << endl;
6196  cerr << "Error : indices were not found in lists " << endl;
6197  cerr << " p1 and/or p2 did not appear in vec " << endl;
6198  cerr << " in " << __PRETTY_FUNCTION__ << endl;
6199  RSVS3D_ERROR_ARGUMENT("Incompatible list and index");
6200  }
6201 
6202  retVal = (ord1 == ord2) * 2 - 1;
6203 #ifdef SAFE_ALGO
6204  int retValOld = OrderMatchLists_old(vec1, vec2, p1, p2);
6205  if (retVal != retValOld)
6206  {
6207  cerr << endl;
6208  DisplayVector(vec1);
6209  DisplayVector(vec2);
6210  cerr << endl << "p " << p1 << "," << p2 << endl;
6211  cerr << endl << "retVal (new,old): " << retVal << "," << retValOld << endl;
6212  RSVS3D_ERROR_LOGIC("Legacy and new versions do not match.");
6213  }
6214 #endif
6215  return (retVal);
6216 }
6217 
6218 void ConnVertFromConnEdge(const mesh &meshin, const vector<int> &edgeind, vector<int> &vertind)
6219 {
6220  // Returns a list of connected vertices matching a list of connected edges
6221  bool flag;
6222  int kk, ll, nEdge;
6223 
6224  nEdge = int(edgeind.size());
6225  if (vertind.size() > 0)
6226  {
6227  RSVS3D_ERROR_ARGUMENT("verting is expected to be an empty vector.");
6228  }
6229  vertind.reserve(nEdge);
6230  ll = 0;
6231  kk = 0;
6232  flag = (meshin.edges.isearch(edgeind[kk])->vertind[ll] == meshin.edges.isearch(edgeind[kk + 1])->vertind[0]) |
6233  (meshin.edges.isearch(edgeind[kk])->vertind[ll] == meshin.edges.isearch(edgeind[kk + 1])->vertind[1]);
6234  if (!flag)
6235  {
6236  ll = ((ll + 1) % 2);
6237  }
6238  for (kk = 0; kk < nEdge; ++kk)
6239  {
6240  vertind.push_back(meshin.edges.isearch(edgeind[kk])->vertind[ll]);
6241 
6242  if (kk < (nEdge - 1))
6243  {
6244  flag =
6245  (meshin.edges.isearch(edgeind[kk])->vertind[0] == meshin.edges.isearch(edgeind[kk + 1])->vertind[ll]) |
6246  (meshin.edges.isearch(edgeind[kk])->vertind[1] == meshin.edges.isearch(edgeind[kk + 1])->vertind[ll]);
6247  ll = ((ll + 1) % 2) * (flag) + ll * (!flag);
6248  }
6249  }
6250 }
6251 
6264 void CropMeshGreedy(mesh &meshin, const std::vector<double> &lb, const std::vector<double> &ub)
6265 {
6266  int nVerts;
6267  std::vector<int> vertDel;
6268 
6269  // Primary deletion (upwards from the vertices)
6270  nVerts = meshin.verts.size();
6271  for (int i = 0; i < nVerts; ++i)
6272  {
6273  for (int j = 0; j < 3; ++j)
6274  {
6275  if (meshin.verts(i)->coord[j] > ub[j] || meshin.verts(i)->coord[j] < lb[j])
6276  {
6277  vertDel.push_back(meshin.verts(i)->index);
6278  break;
6279  }
6280  }
6281  }
6282  meshin.Crop(vertDel, 1);
6283 }
6284 
6293 mesh Points2Mesh(const std::vector<double> &vecPts, int nProp)
6294 {
6295  mesh meshpts;
6296 
6297  if ((vecPts.size() % nProp) != 0)
6298  {
6299  std::cerr << "Error in: " << __PRETTY_FUNCTION__ << std::endl;
6300  RSVS3D_ERROR_ARGUMENT("Vector of points is an invalid size");
6301  }
6302  int nPts = vecPts.size() / nProp;
6303  meshpts.Init(nPts, 0, 0, 0);
6304  meshpts.PopulateIndices();
6305  for (int i = 0; i < nPts; ++i)
6306  {
6307  for (int j = 0; j < 3; ++j)
6308  {
6309  meshpts.verts[i].coord[j] = vecPts[i * nProp + j];
6310  }
6311  }
6312  meshpts.verts.PrepareForUse();
6313  return (meshpts);
6314 }
6315 
6316 namespace meshhelp
6317 {
6318 /*
6319 A namespace of helper function not designed to be propagated throughout
6320 */
6321 void PlaceBorderVertex(const std::vector<double> &coordIn, const std::vector<double> &coordOut,
6322  const std::vector<double> &lb, const std::vector<double> &ub, std::vector<double> &coordTarg)
6323 {
6324  for (int i = 0; i < 3; ++i)
6325  {
6326  coordTarg[i] = coordIn[i] - coordOut[i];
6327  }
6328 
6329  double lStep = meshhelp::ProjectRay(3, vector<vector<double>>({lb, ub}), coordTarg, coordIn, 0.0);
6330 
6331 #ifdef SAFE_ALGO
6332  if (lStep > +0.0 || lStep < -1.001)
6333  {
6334  cout << "Error in: " << __PRETTY_FUNCTION__ << endl << " coordIn : ";
6335  DisplayVector(coordIn);
6336  cout << " coordOut : ";
6337  DisplayVector(coordOut);
6338  cout << " coordTarg : ";
6339  DisplayVector(coordTarg);
6340  cout << endl << "lStep : " << lStep << endl;
6341  RSVS3D_ERROR_LOGIC("The lstep for a vertex should be between 0"
6342  " and 1 for it to lie on the original edge.");
6343  }
6344 #endif // SAFE_ALGO
6345 
6346  for (int i = 0; i < 3; ++i)
6347  {
6348  coordTarg[i] = coordTarg[i] * lStep + coordIn[i];
6349  }
6350 }
6351 
6352 void SplitBorderSurfaceEdgeind(const mesh &meshin, const std::vector<bool> &edgeOut, std::vector<int> &vecconnIn,
6353  std::vector<int> &vecconnOut)
6354 {
6355  /*
6356  Splits the connectivity of a surface lying on the border into
6357  those edges lying inside and outside of the new forming boundary
6358 
6359  this needs to be templated
6360  */
6361 
6362  vecconnOut.clear();
6363  int count = vecconnIn.size();
6364  auto temp = meshin.edges.find_list(vecconnIn, true);
6365  vecconnIn.clear();
6366  for (int i = 0; i < count; ++i)
6367  {
6368  if (temp[i] == -1)
6369  {
6370  std::cerr << "Error in : " << __PRETTY_FUNCTION__ << std::endl;
6371  RSVS3D_ERROR_ARGUMENT("Edge index in connectivity list"
6372  " not found");
6373  }
6374  if (edgeOut[temp[i]])
6375  {
6376  vecconnOut.push_back(meshin.edges(temp[i])->index);
6377  }
6378  else
6379  {
6380  vecconnIn.push_back(meshin.edges(temp[i])->index);
6381  }
6382  }
6383 }
6384 
6396 void HandleMultiSurfaceSplit(mesh &meshin, vector<int> &edgeindOld, vector<int> &edgeindNew, vector<int> &vertindNew)
6397 {
6398  sort(edgeindNew);
6399  unique(edgeindNew);
6400  auto edgeOrig = edgeindNew;
6401  int outFlag = OrderEdgeList(edgeindNew, meshin, false, false, &edgeOrig);
6402  // trim edgeind
6403  if (outFlag != rsvsorder::truncated)
6404  {
6405  edgeindNew.erase(edgeindNew.begin() - outFlag, edgeindNew.end());
6406  }
6407  for (auto edgeIndAll : edgeOrig)
6408  {
6409  bool flag = true;
6410  for (auto edgeindOut : edgeindNew)
6411  {
6412  if (edgeIndAll == edgeindOut)
6413  {
6414  flag = false;
6415  break;
6416  }
6417  }
6418  if (flag)
6419  {
6420  edgeindOld.push_back(edgeIndAll);
6421  }
6422  }
6423  if (outFlag >= 0)
6424  {
6425  RSVS3D_ERROR_LOGIC("The result of OrderEdgeList should be "
6426  "negative to indicate an open surface");
6427  }
6428  std::array<int, 2> inds;
6429  int k = 0;
6430  int nVertExtra = vertindNew.size();
6431  for (auto edgei : edgeindNew)
6432  {
6433  int temp = meshin.edges.find(edgei);
6434  for (int j = 0; j < 2; ++j)
6435  {
6436  for (int l = 0; l < nVertExtra; ++l)
6437  {
6438  if (vertindNew[l] == meshin.edges(temp)->vertind[j])
6439  {
6440  inds[k++] = l;
6441  break;
6442  }
6443  }
6444  if (k == 2)
6445  {
6446  break;
6447  }
6448  }
6449  if (k == 2)
6450  {
6451  break;
6452  }
6453  }
6454  vertindNew = {vertindNew[inds[0]], vertindNew[inds[1]]};
6455 }
6456 
6457 void SplitBorderVolumeSurfind(const mesh &meshin, const std::vector<bool> &edgeOut, std::vector<int> &vecconnIn,
6458  std::vector<int> &vecconnOut)
6459 {
6460  /*
6461  Splits the connectivity of a volume lying on the border into
6462  those surfs lying inside and outside of the new forming boundary
6463 
6464  this needs to be templated
6465  */
6466 
6467  vecconnOut.clear();
6468  int count = vecconnIn.size();
6469  auto temp = meshin.surfs.find_list(vecconnIn, true);
6470  vecconnIn.clear();
6471  for (int i = 0; i < count; ++i)
6472  {
6473  if (temp[i] == -1)
6474  {
6475  std::cerr << "Error in : " << __PRETTY_FUNCTION__ << std::endl;
6476  RSVS3D_ERROR_ARGUMENT("Edge index in connectivity list "
6477  "not found");
6478  }
6479  if (edgeOut[temp[i]])
6480  {
6481  vecconnOut.push_back(meshin.surfs(temp[i])->index);
6482  }
6483  else
6484  {
6485  vecconnIn.push_back(meshin.surfs(temp[i])->index);
6486  }
6487  }
6488 }
6489 
6490 std::vector<int> FindVertInFromEdgeOut(const mesh &meshin, const std::vector<bool> &vertOut,
6491  const std::vector<int> &edgeList, const std::vector<int> &edgeListCheck)
6492 {
6493  /*
6494  Returns the vertices which are in (false in vertOut) from a list of
6495  edges which are outside.
6496 
6497  This may be larger than two as edgeList are not guaranteed to be part
6498  of a single surface. If there are two cuts this would yield 4 vertices.
6499  */
6500  std::vector<int> vertList;
6501  int count = edgeList.size();
6502  for (int i = 0; i < count; ++i)
6503  {
6504  for (int j = 0; j < 2; ++j)
6505  {
6506  int temp = meshin.edges.isearch(edgeList[i])->vertind[j];
6507  if (!vertOut[meshin.verts.find(temp)])
6508  {
6509  vertList.push_back(temp);
6510  }
6511  }
6512  }
6513  sort(vertList);
6514  unique(vertList);
6515  if (vertList.size() != 2)
6516  {
6517  // DisplayVector(vertList);
6518  std::vector<int> vertListTemp = {};
6519  vertList.swap(vertListTemp);
6520 
6521  for (auto k : edgeListCheck)
6522  { //
6523  for (auto i : meshin.edges.isearch(k)->vertind)
6524  {
6525  for (int j : vertListTemp)
6526  {
6527  if (i == j)
6528  {
6529  vertList.push_back(i);
6530  break;
6531  }
6532  }
6533  }
6534  }
6535  }
6536  sort(vertList);
6537  unique(vertList);
6538 
6539  return (vertList);
6540 }
6541 std::vector<int> FindEdgeInFromSurfOut(const mesh &meshin, const std::vector<bool> &edgeOut, std::vector<int> surfList)
6542 {
6543  /*
6544  Returns the edgeices which are in (false in edgeOut) from a list of
6545  surfs which are outside.
6546 
6547  Needs to be templated
6548  */
6549  std::vector<int> edgeList;
6550  int count = surfList.size();
6551  for (int i = 0; i < count; ++i)
6552  {
6553  for (auto temp : meshin.surfs.isearch(surfList[i])->edgeind)
6554  {
6555  if (!edgeOut[meshin.edges.find(temp)])
6556  {
6557  edgeList.push_back(temp);
6558  }
6559  }
6560  }
6561 
6562  return (edgeList);
6563 }
6564 
6576 int Get3PointsInSurface(const mesh &meshin, int surfCurr, std::array<int, 3> &surfacePoints)
6577 {
6578  int surfacePointsIdentified = 0;
6579  for (auto edgeCurr : meshin.surfs.isearch(surfCurr)->edgeind)
6580  {
6581  if (meshin.edges.isearch(edgeCurr)->IsLength0(meshin))
6582  {
6583  continue;
6584  }
6585  if (surfacePointsIdentified == 0)
6586  {
6587  surfacePoints[0] = meshin.edges.isearch(edgeCurr)->vertind[0];
6588  surfacePoints[1] = meshin.edges.isearch(edgeCurr)->vertind[1];
6589  surfacePointsIdentified = 2;
6590  }
6591  else
6592  {
6593  for (auto vertCurr : meshin.edges.isearch(edgeCurr)->vertind)
6594  {
6595  if (vertCurr != surfacePoints[0] && vertCurr != surfacePoints[1] &&
6596  !(meshhelp::IsVerticesDistance0(meshin, {vertCurr, surfacePoints[0]})) &&
6597  !(meshhelp::IsVerticesDistance0(meshin, {vertCurr, surfacePoints[1]})))
6598  {
6599  surfacePoints[2] = vertCurr;
6600  surfacePointsIdentified++;
6601  break;
6602  }
6603  }
6604  }
6605  if (surfacePointsIdentified == 3)
6606  {
6607  break;
6608  }
6609  }
6610  return surfacePointsIdentified;
6611 }
6612 
6613 int VertexInVolume(const mesh &meshin, const vector<double> testCoord, bool needFlip)
6614 {
6615  /*
6616  for each point
6617  Start at a surface (any)
6618  Find which side it is on
6619  -> gives me a candidate volume
6620  -> candidate volume is stored and provides a list of
6621  surfaces to test against
6622  -> if candidate is 0 and outside of the mesh convex its done.
6623  */
6624 
6625  if (meshin.volus.size() == 0)
6626  {
6627  return 0;
6628  }
6629  coordvec temp1, temp2;
6630  std::array<int, 3> surfacePoints = {0, 0, 0};
6631  bool isInCandidate = false, candidateIsValid;
6632  int volumeCandidate = 0;
6633  int pointInVolu, alternateVolume, nVolusExplored = 0, nVolus;
6634  double distToPlane, multiplierDist;
6635  multiplierDist = needFlip ? -1.0 : 1.0;
6636  nVolus = meshin.volus.size();
6637  volumeCandidate = meshin.volus(0)->index;
6638  do
6639  {
6640  // assume the vertex is out of the candidate
6641  isInCandidate = true;
6642  candidateIsValid = false;
6643  // for each face of the candidate volume
6644  for (auto surfCurr : meshin.volus.isearch(volumeCandidate)->surfind)
6645  {
6646 #ifdef SAFE_ALGO
6647  // Checks that ordering and edgeind are correct
6648  if (!meshin.surfs.isearch(surfCurr)->isready(true))
6649  {
6650  RSVS3D_ERROR_ARGUMENT("Surfaces of `meshin` need to be "
6651  "ordered. Run meshin.OrderEdges() before calling");
6652  }
6653  if (meshin.surfs.isearch(surfCurr)->edgeind.size() < 3)
6654  {
6655  std::string strErr;
6656  strErr = "Surface " + to_string(surfCurr) + " has less than 3 edges.";
6657  RSVS3D_ERROR_ARGUMENT(strErr.c_str());
6658  }
6659 #endif
6660 
6661  // assign surfacePoints the indices of 3 non coincident
6662  // points appearing in the surface
6663  int surfacePointsIdentified = Get3PointsInSurface(meshin, surfCurr, surfacePoints);
6664  if (surfacePointsIdentified != 3)
6665  {
6666  // if the surface has less than 3 non-coincident points it
6667  // is degenerate and equivalent to an edge. It does not
6668  // invalidate or validate the candidate
6669  int jj = meshin.surfs.isearch(surfCurr)->voluind[0] == volumeCandidate;
6670  alternateVolume = meshin.surfs.isearch(surfCurr)->voluind[jj];
6671  continue;
6672  }
6673  // candidate is valid if it has one non-degenerate face
6674  candidateIsValid = true;
6675  distToPlane = VertexDistanceToPlane(meshin.verts.isearch(surfacePoints[0])->coord,
6676  meshin.verts.isearch(surfacePoints[1])->coord,
6677  meshin.verts.isearch(surfacePoints[2])->coord, testCoord, temp1, temp2);
6678  if (fabs(distToPlane) < __DBL_EPSILON__)
6679  {
6680  continue;
6681  }
6682  pointInVolu = meshin.surfs.isearch(surfCurr)->voluind[int((distToPlane * multiplierDist) > 0)];
6683  if (pointInVolu == 0)
6684  {
6685  volumeCandidate = pointInVolu;
6686  break;
6687  }
6688  else if (pointInVolu != volumeCandidate)
6689  {
6690  isInCandidate = false;
6691  volumeCandidate = pointInVolu;
6692  break;
6693  }
6694  }
6695  if (!candidateIsValid && isInCandidate)
6696  {
6697  isInCandidate = false;
6698  volumeCandidate = alternateVolume;
6699  }
6700  nVolusExplored++;
6701  } while (!isInCandidate && nVolusExplored < nVolus);
6702  if (!isInCandidate)
6703  {
6704  RSVS3D_ERROR_LOGIC("Algorithm did not find the cell in which the"
6705  " vertex lies.");
6706  }
6707 #ifdef RSVS_DIAGNOSTIC_RESOLVED
6708  cout << nVolusExplored << " ";
6709 #endif
6710  return volumeCandidate;
6711 }
6712 
6713 double VerticesDistanceSquared(const mesh &meshin, const vector<int> &vertind)
6714 {
6715  double lengthSquared = 0.0;
6716 
6717  for (int i = 0; i < meshin.WhatDim(); ++i)
6718  {
6719  lengthSquared +=
6720  pow(meshin.verts.isearch(vertind[0])->coord[i] - meshin.verts.isearch(vertind[1])->coord[i], 2.0);
6721  }
6722 
6723  return lengthSquared;
6724 }
6725 double VerticesDistance(const mesh &meshin, const vector<int> &vertind)
6726 {
6727  return sqrt(VerticesDistanceSquared(meshin, vertind));
6728 }
6729 bool IsVerticesDistance0(const mesh &meshin, const vector<int> &vertind, double eps)
6730 {
6731  return VerticesDistanceSquared(meshin, vertind) < pow(eps, 2.0);
6732 }
6733 } // namespace meshhelp
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 an edge object in a mesh.
Definition: mesh.hpp:353
double Length(const mesh &meshin) const
Calculate the edge length.
Definition: mesh.cpp:1496
double LengthSquared(const mesh &meshin) const
Calculate squared edge length.
Definition: mesh.cpp:1477
bool IsLength0(const mesh &meshin, double eps=__DBL_EPSILON__) const
Returns.
Definition: mesh.cpp:1514
void GeometricProperties(const mesh *meshin, coordvec &centre, double &length) const
Math operations in mesh.
Definition: mesh.cpp:1456
Class for mesh handling.
Definition: mesh.hpp:592
std::vector< int > AddBoundary(const std::vector< double > &lb, const std::vector< double > &ub)
Adds boundaries alond max and min xyz planes.
Definition: mesh.cpp:5357
void LinearTransform(const grid::transformation &transform)
Applies a linear transformation to the points on a grid.
Definition: mesh.cpp:5207
void LinearTransformFamily(const grid::transformation &transform)
Applies a linear transform to child and parent meshes.
Definition: mesh.cpp:5225
void _LinearTransformGeneration(const grid::transformation &transform, std::vector< mesh * > meshdependence::*mp)
Applies reccursively linear transforms to a tree of meshes.
Definition: mesh.cpp:5238
std::vector< int > VertexInVolume(const std::vector< double > testVertices, int sizeVert=3) const
Finds for each vertex, the volume object containing it.
Definition: mesh.cpp:492
int VertFromVertEdge(int v, int e) const
Returns the vertex in edges.isearch(e)->vertind which does not match v.
Definition: mesh.cpp:5926
int ConnectedVertex(std::vector< int > &vertBlock) const
Return in a vector for each vertex a block number which it is part of.
Definition: mesh.cpp:4633
int SurfFromEdges(int e1, int e2, int repetitionBehaviour=-1) const
Returns the index of the surface connecting two edges.
Definition: mesh.cpp:5872
void OrientFaces()
Orients either surfaces or edges depending on the dimensionality of the object.
Definition: mesh.cpp:4948
Class for connecting meshes.
Definition: mesh.hpp:530
std::vector< mesh * > parentmesh
Vector of pointers to the mesh which are coarser (parents).
Definition: mesh.hpp:538
std::vector< mesh * > childmesh
Vector of pointers to the mesh which are finer (children).
Definition: mesh.hpp:540
Class for surface object in a mesh.
Definition: mesh.hpp:267
coordvec PseudoCentroid(const mesh &meshin) const
Calculates the length weighted pseudo-centroid of a surface.
Definition: mesh.cpp:556
Class for a vertex in a mesh.
Definition: mesh.hpp:448
Class for volume cell objects in a mesh.
Definition: mesh.hpp:197
std::vector< int > vertind(const mesh &meshin) const
Get all the vertices a volume is connected to.
Definition: mesh.cpp:1919
coordvec PseudoCentroid(const mesh &meshin) const
Calculates the length weighted pseudo-centroid of a volume.
Definition: mesh.cpp:610
Provides all the mesh tools used for the generation of 3D grids and geometries.
std::vector< const std::vector< double > * > coordlist
Defines a list of coordinates.
Definition: mesh.hpp:87
std::tuple< coordvec, double > VertexNormal(const std::vector< double > &centre, const grid::coordlist &vecPts)
Calculates the vertex normal weighted by surface angle partitions.
Definition: mesh.cpp:747
mesh Points2Mesh(const std::vector< double > &vecPts, int nProp=3)
Takes in a set of points and returns a mesh of points ready for voronisation.
Definition: mesh.cpp:6293
double PlaneNormalAndAngle(const std::vector< double > &planeVert1, const std::vector< double > &planeVert2, const std::vector< double > &planeVert3, coordvec &normal, coordvec &temp1)
Calculates a plane's normal vector.
Definition: mesh.cpp:352
void PlaneNormal(const std::vector< double > &planeVert1, const std::vector< double > &planeVert2, const std::vector< double > &planeVert3, coordvec &normal, coordvec &temp1)
Calculates a plane's normal vector.
Definition: mesh.cpp:333
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
void DiffPoints(const std::vector< double > &vert1, const std::vector< double > &vert2, coordvec &diffVerts)
Computes vector between vertices to then compute angles and plane normals.
Definition: mesh.cpp:296
std::array< std::array< double, 3 >, 3 > transformation
Defines a linear transformation to the mesh where for each dimension: {new minimum,...
Definition: mesh.hpp:85
std::vector< double > VerticesDistanceToPlane(const std::vector< double > &planeVert1, const std::vector< double > &planeVert2, const std::vector< double > &planeVert3, const std::vector< double > &testVertices, coordvec &temp1, coordvec &temp2)
Calculates the distance from a set of vertices to a plane.
Definition: mesh.cpp:438
int OrderEdgeList(std::vector< int > &edgeind, const mesh &meshin, bool warn=true, bool errout=true, const std::vector< int > *edgeIndOrigPtr=NULL, const surf *surfin=NULL)
Orders a list of edge to be connected.
Definition: mesh.cpp:3287
int OrderList(std::vector< int > &edgeind, const std::vector< int > &edge2Vert, bool warn=true, bool errout=true, const std::vector< int > *edgeIndOrigPtr=NULL)
Orders a list of elements defined by pairs of indices.
Definition: mesh.cpp:3449
void CropMeshGreedy(mesh &meshin, const std::vector< double > &lb, const std::vector< double > &ub)
Crops a mesh to only the elements inside the cropBox.
Definition: mesh.cpp:6264
void DiffPointsFromCentre(const std::vector< double > &centre, const std::vector< double > &planeVert2, const std::vector< double > &planeVert3, coordvec &normal, coordvec &temp1)
Computes vector between vertices to then compute angles and plane normals.
Definition: mesh.cpp:313
double VertexDistanceToPlane(const std::vector< double > &planeVert1, const std::vector< double > &planeVert2, const std::vector< double > &planeVert3, const std::vector< double > &testVertex, coordvec &temp1, coordvec &temp2)
Calculates the distance from a vertex to a plane.
Definition: mesh.cpp:400
int NormalShouldFlip(const std::vector< int > orderedList, int elm1, int elm2, const std::vector< int > &voluind, bool innerComparison)
Answers if a normal should be flipped to point towards the outside of a volume.
Definition: mesh.cpp:777
int sign(T val)
Returns the sign of a type comparable to 0.
Definition: warning.hpp:215
void error(const char *message="", const char *caller="", const char *file="", int line=0, bool throwError=true)
Custom error function.
Definition: warning.hpp:203
Provides various utility functions for the RSVS operation.
Provides the error and warning system used by the RSVS3D project.
#define RSVS3D_ERROR_LOGIC(M)
Throw a logic_error.
Definition: warning.hpp:139
#define RSVS3D_ERROR_NOTHROW(M)
Generic rsvs warning.
Definition: warning.hpp:120
void CheckFStream(const T &file, const char *callerID, const std::string &fileName)
Checks a file stream.
Definition: warning.hpp:187
#define RSVS3D_ERROR(M)
Throw generic rsvs errors.
Definition: warning.hpp:113
#define RSVS3D_ERROR_RANGE(M)
Throw a range_error.
Definition: warning.hpp:173
#define RSVS3D_ERROR_ARGUMENT(M)
Throw a invalid_argument.
Definition: warning.hpp:148