OBBox.cpp
1 /*---------------------------------------------------------------------------*\
2  *
3  * mimmo
4  *
5  * Copyright (C) 2015-2021 OPTIMAD engineering Srl
6  *
7  * -------------------------------------------------------------------------
8  * License
9  * This file is part of mimmo.
10  *
11  * mimmo is free software: you can redistribute it and/or modify it
12  * under the terms of the GNU Lesser General Public License v3 (LGPL)
13  * as published by the Free Software Foundation.
14  *
15  * mimmo is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18  * License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with mimmo. If not, see <http://www.gnu.org/licenses/>.
22  *
23  \ *---------------------------------------------------------------------------*/
24 
25 #include "OBBox.hpp"
26 #include <lapacke.h>
27 
28 namespace mimmo{
29 
32  m_name = "mimmo.OBBox";
33  m_origin.fill(0.0);
34  m_span.fill(1.0);
35  int counter = 0;
36  for(auto &val : m_axes) {
37  val.fill(0.0);
38  val[counter] = 1.0;
39  ++counter;
40  }
42  m_writeInfo = false;
43 };
44 
49 OBBox::OBBox(const bitpit::Config::Section & rootXML){
50 
51  m_name = "mimmo.OBBox";
52  m_origin.fill(0.0);
53  m_span.fill(1.0);
54  int counter = 0;
55  for(auto &val : m_axes) {
56  val.fill(0.0);
57  val[counter] = 1.0;
58  ++counter;
59  }
61  m_writeInfo = false;
62 
63  std::string fallback_name = "ClassNONE";
64  std::string input = rootXML.get("ClassName", fallback_name);
65  input = bitpit::utils::string::trim(input);
66  if(input == "mimmo.OBBox"){
67  absorbSectionXML(rootXML);
68  }else{
70  };
71 }
72 
75 
79 OBBox::OBBox(const OBBox & other):BaseManipulation(other){
80  m_origin = other.m_origin;
81  m_span = other.m_span;
82  m_axes = other.m_axes;
83  m_listgeo = other.m_listgeo;
84  m_strategy = other.m_strategy;
85  m_writeInfo = other.m_writeInfo;
86 };
87 
92 void OBBox::swap(OBBox & x) noexcept
93 {
94  std::swap(m_origin, x.m_origin);
95  std::swap(m_span, x.m_span);
96  std::swap(m_axes, x.m_axes);
97  std::swap(m_listgeo, x.m_listgeo);
98  std::swap(m_strategy, x.m_strategy);
99  std::swap(m_writeInfo, x.m_writeInfo);
100 
102 }
105 void
107 
108  bool built = true;
109  built = (built && createPortIn<MimmoSharedPointer<MimmoObject>, OBBox>(this, &mimmo::OBBox::setGeometry, M_GEOM,true,1));
110  built = (built && createPortIn<std::vector<MimmoSharedPointer<MimmoObject> >, OBBox>(this, &mimmo::OBBox::setGeometries, M_VECGEOM, true,1));
111  built = (built && createPortOut<darray3E, OBBox>(this, &mimmo::OBBox::getOrigin, M_POINT));
112  built = (built && createPortOut<dmatrix33E, OBBox>(this, &mimmo::OBBox::getAxes, M_AXES));
113  built = (built && createPortOut<darray3E, OBBox>(this, &mimmo::OBBox::getSpan, M_SPAN));
114 
115  m_arePortsBuilt = built;
116 };
117 
119 void
121  clear(); //base manipulation stuff clear
122  m_origin.fill(0.0);
123  m_span.fill(1.0);
124  m_listgeo.clear();
125  int counter = 0;
126  for(auto &val : m_axes) {
127  val.fill(0.0);
128  val[counter] = 1.0;
129  ++counter;
130  }
132  m_writeInfo = false;
133 };
134 
139 darray3E
141  return(m_origin);
142 }
143 
148 darray3E
150  return(m_span);
151 }
152 
153 
160 
161  return(m_axes);
162 }
163 
167 std::vector<MimmoSharedPointer<MimmoObject> >
169  std::vector<MimmoSharedPointer<MimmoObject> > result;
170  result.reserve(m_listgeo.size());
171  for(auto pp: m_listgeo)
172  result.push_back(pp.first);
173  return result;
174 };
175 
179 bool
181  return (m_strategy == OBBStrategy::AABB);
182 }
183 
189  return m_strategy;
190 }
191 
192 
198 void
200  m_listgeo.clear();
201  for( auto val : listgeo){
202  setGeometry(val);
203  }
204 };
205 
211 void
213 
214  if (geo == nullptr) {
215  (*m_log)<<"warning: "<<m_name<<" not valid Geometry pointer. Doing nothing"<<std::endl;
216  return;
217  }
218 
219  if (geo->getType() == 2 ) {
220  (*m_log)<<"warning: "<<m_name<<" does not support volumetric tessellation. Geometry not set"<<std::endl;
221  return;
222  }
223 
224  m_listgeo.insert(std::make_pair(geo, geo->getType()));
225 };
226 
231 void
234  if (flag) m_strategy = OBBStrategy::AABB;
235 }
236 
241 void
243  m_strategy = strategy;
244 }
245 
250 void
251 OBBox::setOBBStrategyInt(int strategyflag){
252  strategyflag = std::min(2, std::max(strategyflag, 0));
253  m_strategy = static_cast<OBBStrategy>(strategyflag);
254 }
255 
256 
261 void
263  m_writeInfo = flag;
264 }
265 
272 void
273 OBBox::plot(std::string directory, std::string filename,int counter, bool binary){
274 
275 #if MIMMO_ENABLE_MPI
276  if(m_rank == 0){
277 #endif
278 
279  dvecarr3E activeP(8);
280 
281  activeP[0] = - 0.5 * m_span;
282  activeP[6] = 0.5 * m_span;
283 
284  activeP[1] = activeP[0]; activeP[1][0] += m_span[0];
285  activeP[3] = activeP[0]; activeP[3][1] += m_span[1];
286  activeP[2] = activeP[6]; activeP[2][2] += -1.0*m_span[2];
287 
288  activeP[7] = activeP[6]; activeP[7][0] += -1.0*m_span[0];
289  activeP[5] = activeP[6]; activeP[5][1] += -1.0*m_span[1];
290  activeP[4] = activeP[0]; activeP[4][2] += m_span[2];
291 
292  darray3E temp;
293  dmatrix33E inv = inverse(m_axes);
294  for(auto &val : activeP){
295  for(int i=0; i<3; ++i){
296  temp[i] = dotProduct(val, inv[i]);
297  }
298  val = temp + m_origin;
299  }
300 
301  ivector2D activeConn(1);
302  for(int i=0; i<8; ++i) activeConn[0].push_back(i);
303 
304  bitpit::VTKFormat codex = bitpit::VTKFormat::ASCII;
305  if(binary){codex=bitpit::VTKFormat::APPENDED;}
306  bitpit::VTKElementType elDM = bitpit::VTKElementType::HEXAHEDRON;
307  bitpit::VTKUnstructuredGrid vtk(directory, filename, elDM);
308  vtk.setGeomData( bitpit::VTKUnstructuredField::POINTS, activeP) ;
309  vtk.setGeomData( bitpit::VTKUnstructuredField::CONNECTIVITY, activeConn) ;
310  vtk.setDimensions(1, 8);
311  vtk.setCodex(codex);
312  if(counter>=0){vtk.setCounter(counter);}
313 
314  vtk.write();
315 
316 #if MIMMO_ENABLE_MPI
317  }
318  MPI_Barrier(m_communicator);
319 #endif
320 
321 }
322 
323 
328 void
330 
331  // check if the list is empty.
332  if(m_listgeo.empty()){
333  m_span.fill(0.0);
334  m_origin.fill(0.0);
335  m_axes[0]={{1.,0.,0.}};
336  m_axes[1]={{0.,1.,0.}};
337  m_axes[2]={{0.,0.,1.}};
338 
339  *m_log<<"Warning in "<<m_name<<" : no external geometry provided"<<std::endl;
340  return;
341  };
342 
343 
344  std::vector<MimmoSharedPointer<MimmoObject>> vector_listgeo = getGeometries();
345 
346  darray3E originOBB, spanOBB, originAABB, spanAABB;
347  dmatrix33E axesOBB, axesAABB;
348  switch(m_strategy){
349  case OBBStrategy::OBB :
350  computeOBB(vector_listgeo, originOBB, spanOBB, axesOBB);
351  std::swap(m_origin, originOBB);
352  std::swap(m_span, spanOBB);
353  std::swap(m_axes, axesOBB);
354  break;
355  case OBBStrategy::AABB :
356  computeAABB(vector_listgeo, originAABB, spanAABB, axesAABB);
357  std::swap(m_origin, originAABB);
358  std::swap(m_span, spanAABB);
359  std::swap(m_axes, axesAABB);
360  break;
361  case OBBStrategy::MINVOL :
362  computeOBB(vector_listgeo, originOBB, spanOBB, axesOBB);
363  computeAABB(vector_listgeo, originAABB, spanAABB, axesAABB);
364 
365  if(spanOBB[0]*spanOBB[1]*spanOBB[2] < spanAABB[0]*spanAABB[1]*spanAABB[2] ){
366  std::swap(m_origin, originOBB);
367  std::swap(m_span, spanOBB);
368  std::swap(m_axes, axesOBB);
369  }else{
370  std::swap(m_origin, originAABB);
371  std::swap(m_span, spanAABB);
372  std::swap(m_axes, axesAABB);
373  }
374  break;
375  default: //never been reached
376  break;
377  }
378 
379  if (!m_writeInfo) return;
380  //OK, write the resume file.
381 #if MIMMO_ENABLE_MPI
382  //allow only rank-0 to write the resume file
383  if(m_rank == 0)
384  {
385 #endif
386  std::ofstream out;
387  out.open(m_outputPlot+"/"+m_name+std::to_string(getId())+"_INFO.dat");
388  if(out.is_open()){
389  out<<"OBBox "<<std::to_string(getId())<<" info:"<<std::endl;
390  out<<std::endl;
391  out<<std::endl;
392  out<<"Origin: "<<std::scientific<<m_origin<<std::endl;
393  out<<std::endl;
394  out<<"Axis 0: "<<std::scientific<<m_axes[0]<<std::endl;
395  out<<"Axis 1: "<<std::scientific<<m_axes[1]<<std::endl;
396  out<<"Axis 2: "<<std::scientific<<m_axes[2]<<std::endl;
397  out<<std::endl;
398  out<<"Span: "<<std::scientific<<m_span<<std::endl;
399  out.close();
400  }
401 #if MIMMO_ENABLE_MPI
402  }
403  MPI_Barrier(m_communicator); //force all other ranks to wait rank0 here.
404 #endif
405 
406 };
407 
415 void
417  darray3E & origin, darray3E &span, dmatrix33E & axes)
418 {
419 
420 //if one geometry at least is a cloud point, solve them all as point clouds.
421  bool allCloud = false;
422  for(MimmoSharedPointer<MimmoObject> & ptr : vector_listgeo){
423  allCloud = allCloud || (ptr->getType() == 3 || ptr->getType() == 4);
424  }
425 
426  //calculate the right system of axes
427  dmatrix33E covariance;
428  darray3E spectrum;
429  if(allCloud){
430  covariance = evaluatePointsCovarianceMatrix(vector_listgeo); //global collective for MPI
431  }else{
432  covariance = evaluateElementsCovarianceMatrix(vector_listgeo); //global collective for MPI
433  }
434 
435  axes = eigenVectors(covariance, spectrum);
436  adjustBasis(axes, spectrum);
437 
438  darray3E pmin, pmax;
439  double val;
440  pmin.fill(std::numeric_limits<double>::max());
441  pmax.fill(-1.0*std::numeric_limits<double>::max());
442  //calculate local bounding box
443  for(MimmoSharedPointer<MimmoObject> &ptr : vector_listgeo){
444  livector1D vertIds = ptr->getVerticesIds(true); //only internals.
445  for(long id: vertIds){
446  darray3E coord =ptr->getVertexCoords(id);
447  for(int i=0;i<3; ++i){
448  val = dotProduct(coord, axes[i]);
449  pmin[i] = std::fmin(pmin[i], val);
450  pmax[i] = std::fmax(pmax[i], val);
451  }
452  }
453  }
454 
455 #if MIMMO_ENABLE_MPI
456  //reduce bbox data all over the ranks
457  MPI_Allreduce(MPI_IN_PLACE, pmin.data(), 3, MPI_DOUBLE, MPI_MIN, m_communicator);
458  MPI_Allreduce(MPI_IN_PLACE, pmax.data(), 3, MPI_DOUBLE, MPI_MAX, m_communicator);
459 #endif
460 
461  //recover span and origin of the current box
462  dmatrix33E inv = inverse(axes);
463  span = pmax - pmin;
464  //check if one of the span goes to 0;
465  double avg_span = 0.0;
466  for(double & val: span) avg_span+=val;
467  avg_span /= 3.0;
468 
469  for(double &val : span) {
470  val = std::fmax(val, 1.E-04*avg_span);
471  }
472 
473  darray3E originLoc = 0.5*(pmin+pmax);
474  for(int i=0; i<3; ++i){
475  origin[i] = dotProduct(originLoc, inv[i]);
476  }
477 }
478 
486 void
488  darray3E & origin, darray3E &span, dmatrix33E & axes)
489 {
490 
491  axes[0] = {{1.,0.,0.}};
492  axes[1] = {{0.,1.,0.}};
493  axes[2] = {{0.,0.,1.}};
494 
495  darray3E pmin, pmax;
496  pmin.fill(std::numeric_limits<double>::max());
497  pmax.fill(-1.0*std::numeric_limits<double>::max());
498  //calculate local bounding box
499  for(MimmoSharedPointer<MimmoObject> &ptr : vector_listgeo){
500  livector1D vertIds = ptr->getVerticesIds(true); //only internals.
501  for(long id: vertIds){
502  darray3E coord =ptr->getVertexCoords(id);
503  for(int i=0;i<3; ++i){
504  pmin[i] = std::fmin(pmin[i], coord[i]);
505  pmax[i] = std::fmax(pmax[i], coord[i]);
506  }
507  }
508  }
509 
510 #if MIMMO_ENABLE_MPI
511  //reduce bbox data all over the ranks
512  MPI_Allreduce(MPI_IN_PLACE, pmin.data(), 3, MPI_DOUBLE, MPI_MIN, m_communicator);
513  MPI_Allreduce(MPI_IN_PLACE, pmax.data(), 3, MPI_DOUBLE, MPI_MAX, m_communicator);
514 #endif
515 
516  //recover span and origin of the current box
517  span = pmax - pmin;
518  //check if one of the span goes to 0;
519  double avg_span = 0.0;
520  for(double & val: span) avg_span+=val;
521  avg_span /= 3.0;
522 
523  for(double &val : span) {
524  val = std::fmax(val, 1.E-04*avg_span);
525  }
526 
527  origin = 0.5*(pmin+pmax);
528 
529 }
530 
531 
536 void
538  std::string dir = m_outputPlot ;
539  std::string nameGrid = m_name;
540  plot(dir, nameGrid, getId(), true );
541 }
542 
548 void
549 OBBox::absorbSectionXML(const bitpit::Config::Section & slotXML, std::string name){
550 
551  BITPIT_UNUSED(name);
552  BaseManipulation::absorbSectionXML(slotXML, name);
553 
555  // LEGACY ONLY -TODO to be removed once deprecated setForceAABB will be removed
556  if(slotXML.hasOption("ForceAABB")){
557  std::string input = slotXML.get("ForceAABB");
558  input = bitpit::utils::string::trim(input);
559  bool value = false;
560  if(!input.empty()){
561  std::stringstream ss(input);
562  ss >> value;
563  }
564  if (value) setOBBStrategy(OBBStrategy::AABB);
566  }
568 
569  if(slotXML.hasOption("OBBStrategy")){
570  std::string input = slotXML.get("OBBStrategy");
571  input = bitpit::utils::string::trim(input);
572  int value = 0;
573  if(!input.empty()){
574  std::stringstream ss(input);
575  ss >> value;
576  }
577  setOBBStrategyInt(value);
578  }
579 
580  if(slotXML.hasOption("WriteInfo")){
581  std::string input = slotXML.get("WriteInfo");
582  input = bitpit::utils::string::trim(input);
583  bool value = false;
584  if(!input.empty()){
585  std::stringstream ss(input);
586  ss >> value;
587  }
588  setWriteInfo(value);
589  }
590 
591 }
592 
598 void
599 OBBox::flushSectionXML(bitpit::Config::Section & slotXML, std::string name){
600 
601  BITPIT_UNUSED(name);
602  BaseManipulation::flushSectionXML(slotXML, name);
603 
604  slotXML.set("OBBStrategy", std::to_string(static_cast<int>(m_strategy)));
605  slotXML.set("WriteInfo", std::to_string((int)m_writeInfo));
606 
607 };
608 
609 
617 OBBox::evaluatePointsCovarianceMatrix(std::vector<MimmoSharedPointer<MimmoObject> > list){
618 
619  std::unordered_map<MimmoSharedPointer<MimmoObject>, std::vector<long>> vertIds;
620 
621  //evaluate the mass center first;
622  darray3E masscenter = {{0.0,0.0,0.0}};
623  long countvert = 0;
624  for(MimmoSharedPointer<MimmoObject>& geo: list){
625  vertIds[geo] = geo->getVerticesIds(true); //only internals
626  for(long id : vertIds[geo]){
627  masscenter += geo->getVertexCoords(id);
628  }
629  countvert += long(vertIds[geo].size());
630  }
631 
632 #if MIMMO_ENABLE_MPI
633  //communicate the vert count and the partial masscenter throughout the ranks
634  MPI_Allreduce(MPI_IN_PLACE, &countvert, 1, MPI_LONG, MPI_SUM, m_communicator);
635  MPI_Allreduce(MPI_IN_PLACE, masscenter.data(), 3, MPI_DOUBLE, MPI_SUM, m_communicator);
636 #endif
637  //evaluate the mass center.
638  masscenter /= double(countvert);
639 
640 
641  //assembly locally covariance matrix node by node.
642  dmatrix33E loc;
643  dmatrix33E covariance;
644  for(auto & val:covariance) val.fill(0.0);
645 
646  darray3E temp;
647  for(MimmoSharedPointer<MimmoObject>& geo: list){
648  //evaluate local contributes to covariance
649  for(long id : vertIds[geo]){
650  temp = geo->getVertexCoords(id) - masscenter;
651  for(int j=0; j<3; ++j){
652  for(int k=j; k<3; ++k){
653  loc[j][k] += temp[j]*temp[k];
654  }
655  }
656  }
657  //store temporarely in covariance
658  int counter = 0;
659  for(auto & val: covariance){
660  val += loc[counter];
661  ++counter;
662  }
663  }
664 
665 #if MIMMO_ENABLE_MPI
666  //reduce summing up the covariance matrix mong the ranks
667  MPI_Allreduce(MPI_IN_PLACE, covariance[0].data(), 3, MPI_DOUBLE, MPI_SUM, m_communicator);
668  MPI_Allreduce(MPI_IN_PLACE, covariance[1].data(), 3, MPI_DOUBLE, MPI_SUM, m_communicator);
669  MPI_Allreduce(MPI_IN_PLACE, covariance[2].data(), 3, MPI_DOUBLE, MPI_SUM, m_communicator);
670 #endif
671 
672  //divide by countvert, element by element - countvert already calculated earlier.
673  for(auto & val: covariance){
674  val /= double(countvert);
675  }
676 
677 
678  //just ot be sure and to avoid tiny floating diffs, enforce diagonal simmetry to the matrix.
679  covariance[1][0] = covariance[0][1];
680  covariance[2][0] = covariance[0][2];
681  covariance[2][1] = covariance[1][2];
682 
683  return covariance;
684 };
685 
686 
696 OBBox::evaluateElementsCovarianceMatrix(std::vector<MimmoSharedPointer<MimmoObject> > list){
697 
698  //You need to evaluate the mass center and the 3x3 matrix of the total moments
699  //obtained as the sum of each element moments.
700  // Non triangular cells are approximated as a representative triangle formed by
701  // the first set of 3 non-aligned vertices.
702 
703 
704  darray3E masscenter = {{0.0,0.0,0.0}};
705  //assembly moments matrix cell by cell.
706  dmatrix33E moments;
707  for(auto & val:moments) val.fill(0.0);
708 
709  darray3E p,q,r, centroid;
710  double areatri, areatot(0.0);
711 
712  //locally calculate the masscenter and the moments matrix
713  for(MimmoSharedPointer<MimmoObject>& geo: list){
714 
715  livector1D cellIds = geo->getCellsIds(true); //only internals
716 
717  for(long id : cellIds){
718 
719  std::array<long,3> vids = get3RepPoints(id, geo);
720  if(vids[0] < 0){
721  continue;
722  }
723  p = geo->getVertexCoords(vids[0]);
724  q = geo->getVertexCoords(vids[1]);
725  r = geo->getVertexCoords(vids[2]);
726 
727  areatri = 0.5*norm2(crossProduct(q-p, r-p));
728  centroid = (p+q+r)/3.0;
729  masscenter += areatri*centroid;
730  areatot += areatri;
731 
732  //assemby moments
733  // on-diagonal terms
734  moments[0][0] += areatri*(9.0*centroid[0]*centroid[0] + p[0]*p[0] + q[0]*q[0] + r[0]*r[0])/12.0;
735  moments[1][1] += areatri*(9.0*centroid[1]*centroid[1] + p[1]*p[1] + q[1]*q[1] + r[1]*r[1])/12.0;
736  moments[2][2] += areatri*(9.0*centroid[2]*centroid[2] + p[2]*p[2] + q[2]*q[2] + r[2]*r[2])/12.0;
737 
738  // off-diagonal terms
739  moments[0][1] += areatri*(9.0*centroid[0]*centroid[1] + p[0]*p[1] + q[0]*q[1] + r[0]*r[1])/12.0;
740  moments[0][2] += areatri*(9.0*centroid[0]*centroid[2] + p[0]*p[2] + q[0]*q[2] + r[0]*r[2])/12.0;
741  moments[1][2] += areatri*(9.0*centroid[1]*centroid[2] + p[1]*p[2] + q[1]*q[2] + r[1]*r[2])/12.0;
742  }
743  }// end of cell by cell loop.
744 
745  // ensure symmetry in the moments matrix
746  moments[1][0] = moments[0][1];
747  moments[2][0] = moments[0][2];
748  moments[2][1] = moments[1][2];
749 
750 
751 #if MIMMO_ENABLE_MPI
752  // reduce masscenter, areatot and moments all over the ranks
753  MPI_Allreduce(MPI_IN_PLACE, &areatot, 1, MPI_DOUBLE, MPI_SUM, m_communicator);
754  MPI_Allreduce(MPI_IN_PLACE, masscenter.data(), 3, MPI_DOUBLE, MPI_SUM, m_communicator);
755  MPI_Allreduce(MPI_IN_PLACE, moments[0].data(), 3, MPI_DOUBLE, MPI_SUM, m_communicator);
756  MPI_Allreduce(MPI_IN_PLACE, moments[1].data(), 3, MPI_DOUBLE, MPI_SUM, m_communicator);
757  MPI_Allreduce(MPI_IN_PLACE, moments[2].data(), 3, MPI_DOUBLE, MPI_SUM, m_communicator);
758 #endif
759 
760  //normalize masscenter
761  masscenter /= areatot;
762 
763  //get final covariance matrix
764  dmatrix33E covariance;
765  for(int i=0; i<3; ++i ){
766  for(int j=0; j<3; ++j ){
767  covariance[i][j] = moments[i][j]/areatot - masscenter[i]*masscenter[j];
768  }
769  }
770  return covariance;
771 };
772 
781 OBBox::eigenVectors( dmatrix33E & matrix, darray3E & eigenvalues){
782 
783  dmatrix33E result;
784  double * a = new double [9];
785  double * s = new double[3];
786 
787  int k=0;
788  for(int i=0; i<3; i++){
789  for(int j=0; j<3; j++){
790  //transpose
791  a[k] = matrix[j][i];
792  k++;
793  }
794  }
795 
796  LAPACKE_dsyev( LAPACK_COL_MAJOR, 'V','U', 3, a, 3, s);
797  //eigenvec are returned in a column wise, and with eigenvals s in ascending order.
798 
799  //rearrange the eigvec
800  for (int i=0; i<9; i++){
801  result[i/3][i%3] = a[i];
802  }
803  for(int i=0; i<3; ++i) {
804  result[i] /= norm2(result[i]);
805  eigenvalues[i] = s[i];
806  }
807 
808  //change them in descending order.
809  std::swap(result[0], result[2]);
810  std::swap(eigenvalues[0], eigenvalues[2]);
811 
812  // clean allocations.
813  delete [] a; a = nullptr;
814  delete [] s; s = nullptr;
815 
816  return result;
817 }
818 
828 void
829 OBBox::adjustBasis(dmatrix33E & eigVec, darray3E & eigVal){
830 
831  darray3E diff;
832  double tol = std::numeric_limits<double>::min();
833 
834  diff[0] = std::abs(eigVal[1]-eigVal[0]);
835  diff[1] = std::abs(eigVal[2]-eigVal[1]);
836  diff[2] = std::abs(eigVal[0]-eigVal[2]);
837 
838  //3 real quasi coincident eigenval-> return fundamental axis.
839  if(diff[0]<=tol && diff[1]<=tol && diff[2]<= tol){
840  int counter=0;
841  for(auto & val : eigVec){
842  val.fill(0.0);
843  val[counter] = 1.0;
844  ++counter;
845  }
846  return;
847  }
848 
849  // 3 real distinct eigenval
850  if(diff[0]>tol && diff[1]>tol && diff[2]>tol){
851  //you need a real reference triad here. Check it out
852  if(dotProduct(eigVec[2], crossProduct(eigVec[0], eigVec[1])) < 0.0){
853  eigVec[2] *= -1.0;
854  };
855  return;
856  };
857 
858  int guess = 0, third =1, stable=2;
859 
860  if(diff[1] <= tol) {
861  guess = 1;
862  third = 2;
863  stable= 0;
864  }
865 
866  eigVec[third] = crossProduct(eigVec[stable],eigVec[guess]);
867  double normv = norm2(eigVec[third]);
868  if(normv > std::numeric_limits<double>::min()){
869  eigVec[third] /= normv;
870  }
871 
872  //you need a real reference triad here. Check it out
873  if(dotProduct(eigVec[2], crossProduct(eigVec[0], eigVec[1])) < 0.0){
874  eigVec[2] *= -1.0;
875  };
876 
877 };
878 
879 
886  dmatrix33E out;
887 
888  for(std::size_t i=0; i<3; ++i){
889  for(std::size_t j=0; j<3; ++j){
890  out[j][i] = mat[i][j];
891  }
892  }
893  return out;
894 }
895 
902  dmatrix33E out;
903 
904  double det = mat[0][0] * (mat[1][1]*mat[2][2] - mat[2][1]*mat[1][2]) -
905  mat[0][1] * (mat[1][0]*mat[2][2] - mat[2][0]*mat[1][2]) +
906  mat[0][2] * (mat[1][0]*mat[2][1] - mat[2][0]*mat[1][1]);
907 
908  out[0][0] = (mat[1][1]*mat[2][2] - mat[2][1]*mat[1][2])/det;
909  out[0][1] = (mat[0][2]*mat[2][1] - mat[2][2]*mat[0][1])/det;
910  out[0][2] = (mat[0][1]*mat[1][2] - mat[1][1]*mat[0][2])/det;
911  out[1][0] = (mat[1][2]*mat[2][0] - mat[2][2]*mat[1][0])/det;
912  out[1][1] = (mat[0][0]*mat[2][2] - mat[2][0]*mat[0][2])/det;
913  out[1][2] = (mat[0][2]*mat[1][0] - mat[1][2]*mat[0][0])/det;
914  out[2][0] = (mat[1][0]*mat[2][1] - mat[2][0]*mat[1][1])/det;
915  out[2][1] = (mat[0][1]*mat[2][0] - mat[2][1]*mat[0][0])/det;
916  out[2][2] = (mat[0][0]*mat[1][1] - mat[1][0]*mat[0][1])/det;
917 
918 
919  return out;
920 }
921 
922 
930 std::array<long,3> OBBox::get3RepPoints(long cellID, MimmoSharedPointer<MimmoObject> geo){
931  if(!geo) return{{-1,-1,-1}};
932  bitpit::Cell & cell = geo->getCells().at(cellID);
933  std::array<long,3> result;
934 
935  switch(cell.getType()){
936  case bitpit::ElementType::TRIANGLE:
937  {
938  long * conn = cell.getConnect();
939  result[0] = conn[0];
940  result[1] = conn[1];
941  result[2] = conn[2];
942  }
943  break;
944  case bitpit::ElementType::QUAD:
945  case bitpit::ElementType::POLYGON:
946  {
947  bitpit::ConstProxyVector<long> vertids = cell.getVertexIds();
948  std::size_t ssz= vertids.size();
949 
950  //find a set of 3 points whose cross product is non zero, if you can.
951  darray3E p0,s1,s2;
952  result[0] = vertids[0];
953  p0 = geo->getVertexCoords(result[0]);
954 
955  std::size_t cand = 2;
956  bool found = false;
957 
958  while(cand < ssz && !found){
959  result[1] = vertids[cand-1];
960  result[2] = vertids[cand];
961  s1 = geo->getVertexCoords(result[1]) - p0;
962  s2 = geo->getVertexCoords(result[2]) - p0;
963  found = (norm2(crossProduct(s1,s2)) > 0.0);
964  ++cand;
965  }
966  }
967  break;
968  default:
969  result.fill(-1);
970  break;
971  }
972 
973  return result;
974 }
975 
976 
977 }
void swap(OBBox &x) noexcept
Definition: OBBox.cpp:92
dmatrix33E transpose(const dmatrix33E &mat)
Definition: OBBox.cpp:885
darray3E getOrigin()
Definition: OBBox.cpp:140
bool m_writeInfo
Definition: OBBox.hpp:99
virtual void flushSectionXML(bitpit::Config::Section &slotXML, std::string name="")
Definition: OBBox.cpp:599
dmatrix33E inverse(const dmatrix33E &mat)
Definition: OBBox.cpp:901
void computeAABB(std::vector< MimmoSharedPointer< MimmoObject >> &vector_listgeo, darray3E &origin, darray3E &span, dmatrix33E &axes)
Definition: OBBox.cpp:487
bool isForcedAABB()
Definition: OBBox.cpp:180
#define M_GEOM
std::vector< darray3E > dvecarr3E
virtual void absorbSectionXML(const bitpit::Config::Section &slotXML, std::string name="")
Definition: OBBox.cpp:549
std::vector< long > livector1D
void setGeometry(MimmoSharedPointer< MimmoObject > geo)
Definition: OBBox.cpp:212
#define M_POINT
void warningXML(bitpit::Logger *log, std::string name)
std::vector< MimmoSharedPointer< MimmoObject > > getGeometries()
Definition: OBBox.cpp:168
darray3E m_span
Definition: OBBox.hpp:94
BaseManipulation is the base class of any manipulation object of the library.
void clearOBBox()
Definition: OBBox.cpp:120
void setWriteInfo(bool flag)
Definition: OBBox.cpp:262
OBBStrategy getOBBStrategy()
Definition: OBBox.cpp:188
virtual ~OBBox()
Definition: OBBox.cpp:74
Oriented Bounding Box calculator.
Definition: OBBox.hpp:90
void execute()
Definition: OBBox.cpp:329
OBBStrategy
Enum class for engine choice to set up initial points on a 3D surface.
Definition: OBBox.hpp:36
virtual void absorbSectionXML(const bitpit::Config::Section &slotXML, std::string name="")
std::array< darray3E, 3 > dmatrix33E
void setGeometries(std::vector< MimmoSharedPointer< MimmoObject > > listgeo)
Definition: OBBox.cpp:199
#define M_SPAN
void buildPorts()
Definition: OBBox.cpp:106
#define M_AXES
darray3E m_origin
Definition: OBBox.hpp:93
virtual void flushSectionXML(bitpit::Config::Section &slotXML, std::string name="")
darray3E getSpan()
Definition: OBBox.cpp:149
dmatrix33E getAxes()
Definition: OBBox.cpp:159
std::vector< ivector1D > ivector2D
void setOBBStrategyInt(int strategyflag)
Definition: OBBox.cpp:251
void plot(std::string directory, std::string filename, int counter, bool binary)
Definition: OBBox.cpp:273
dmatrix33E m_axes
Definition: OBBox.hpp:95
std::array< double, 3 > darray3E
void computeOBB(std::vector< MimmoSharedPointer< MimmoObject >> &vector_listgeo, darray3E &origin, darray3E &span, dmatrix33E &axes)
Definition: OBBox.cpp:416
MimmoSharedPointer is a custom implementation of shared pointer.
void setForceAABB(bool flag)
Definition: OBBox.cpp:232
void swap(BaseManipulation &x) noexcept
OBBStrategy m_strategy
Definition: OBBox.hpp:98
std::unordered_map< MimmoSharedPointer< MimmoObject >, int > m_listgeo
Definition: OBBox.hpp:97
void setOBBStrategy(OBBStrategy strategy)
Definition: OBBox.cpp:242
#define M_VECGEOM
virtual void plotOptionalResults()
Definition: OBBox.cpp:537