MEPP2 Project
utils_are_meshes_identical.inl
Go to the documentation of this file.
1 // Copyright (c) 2012-2019 University of Lyon and CNRS (France).
2 // All rights reserved.
3 //
4 // This file is part of MEPP2; you can redistribute it and/or modify
5 // it under the terms of the GNU Lesser General Public License as
6 // published by the Free Software Foundation; either version 3 of
7 // the License, or (at your option) any later version.
8 //
9 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
10 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11 
12 #include <fstream>
13 #include <sstream>
14 #include <iostream>
15 #include <vector>
16 #include <deque>
17 #include <set>
18 #include <utility> // for std::pair
19 #include <algorithm>
20 #include <cmath> // for std::abs()
21 #include <numeric> // for std::accumulate()
22 
23 
25 
26 //------------------------------------------------------------------------------
27 
28 typedef std::set< std::pair< FloatT, FloatT > > ErrorContainer;
29 // A single error value can occur multiple time during mesh comparison,
30 // for example a coordinate that is always rounded in the same way. We
31 // want to keep track of the DIFFERENT errors that occur, so we store
32 // one error as a couple of values (reference value and effective value)
33 // into a set, to get rid of duplicated errors.
34 
35 inline
36 std::string
37 get_next_line(std::ifstream &file);
38 
39 inline
40 FloatT
42 
43 inline FloatT
45 
46 inline
47 bool
48 arevectorequal(const std::vector< FloatT > &v1,
49  const std::vector< FloatT > &v2,
50  FloatT attr_threshold,
51  bool relative_threshold,
52  ErrorContainer *errors_log);
53 
54 //------------------------------------------------------------------------------
55 
56 /*
57  * 3D point class. Points can be sorted in x, y, z order.
58  */
59 class Point
60 {
61 public:
62  Point(FloatT x = 0, FloatT y = 0, FloatT z = 0)
63  {
64  m_x = x;
65  m_y = y;
66  m_z = z;
67  }
68 
69  bool operator<(const Point &p) const
70  {
71  if(m_x < p.m_x)
72  return true;
73  else if(m_x > p.m_x)
74  return false;
75  else if(m_y < p.m_y)
76  return true;
77  else if(m_y > p.m_y)
78  return false;
79  else if(m_z < p.m_z)
80  return true;
81  else if(m_z > p.m_z)
82  return false;
83 
84  return false; // points are equal
85  }
86 
87  // Test if the point coordinates are (almost) equal
88  // to another point coordinates.
89  // A numerical difference is allowed (see threshold)
90  bool isequalto(const Point &p,
91  FloatT geom_threshold,
92  bool relative_threshold,
93  ErrorContainer *errors_log = NULL) const
94  {
95  bool isequal = false;
96  FloatT dist_x;
97  FloatT dist_y;
98  FloatT dist_z;
99 
100  if(geom_threshold == 0.0)
101  {
102  // do an exact comparison
103  isequal = (*this == p);
104  }
105  else if(relative_threshold)
106  {
107  // comparison with a relative threshold
108  dist_x = relative_distance(m_x, p.m_x);
109  dist_y = relative_distance(m_y, p.m_y);
110  dist_z = relative_distance(m_z, p.m_z);
111 
112  isequal = (dist_x <= geom_threshold && dist_y <= geom_threshold &&
113  dist_z <= geom_threshold);
114  }
115  else
116  {
117  // comparison with an absolute threshold
118  dist_x = absolute_distance(m_x, p.m_x);
119  dist_y = absolute_distance(m_y, p.m_y);
120  dist_z = absolute_distance(m_z, p.m_z);
121 
122  isequal = (dist_x <= geom_threshold && dist_y <= geom_threshold &&
123  dist_z <= geom_threshold);
124  }
125 
126  // log errors for future statistics
127  if(!isequal && errors_log)
128  {
129  if(geom_threshold == 0.0)
130  {
131  // case of exact comparison
132  if(m_x != p.m_x)
133  errors_log->insert(std::make_pair(m_x, p.m_x));
134  if(m_y != p.m_y)
135  errors_log->insert(std::make_pair(m_y, p.m_y));
136  if(m_z != p.m_z)
137  errors_log->insert(std::make_pair(m_z, p.m_z));
138  }
139  else
140  {
141  // case of comparison with a threshold
142  if(dist_x > geom_threshold)
143  errors_log->insert(std::make_pair(m_x, p.m_x));
144  if(dist_y > geom_threshold)
145  errors_log->insert(std::make_pair(m_y, p.m_y));
146  if(dist_z > geom_threshold)
147  errors_log->insert(std::make_pair(m_z, p.m_z));
148  }
149  }
150 
151  return isequal;
152  }
153 
154  bool operator==(const Point &p) const
155  {
156  if(m_x == p.m_x && m_y == p.m_y && m_z == p.m_z)
157  return true;
158  return false;
159  }
160 
161  FloatT m_x, m_y, m_z; // point coordinates
162 };
163 
164 inline
165 std::ostream &
166 operator<<(std::ostream &os, const Point &p)
167 {
168  // write obj to stream
169  os << '(' << p.m_x << ' ' << p.m_y << ' ' << p.m_z << ')';
170  return os;
171 }
172 
173 //------------------------------------------------------------------------------
174 
175 class Vertex
176 {
177 public:
178  Vertex(const Point &point, const std::vector< FloatT > &attributes)
179  {
180  m_point = point;
181  m_attributes = attributes;
182  }
183 
184  Vertex &operator=(const Vertex &other) // copy assignment
185  {
186  m_point = other.m_point;
187  m_attributes = other.m_attributes;
188 
189  return *this;
190  }
191 
192  bool operator<(const Vertex &other) const
193  {
194  // if the points are equal, compare the attributes
195  if(m_point == other.m_point)
196  return (m_attributes < other.m_attributes);
197 
198  // if the points are different, compare the points
199  return (m_point < other.m_point);
200  }
201 
202  // compare for equality, a numerical difference is allowed
203  bool isequalto(const Vertex &other,
204  FloatT geom_threshold,
205  FloatT attr_threshold,
206  bool relative_thresholds,
207  ErrorContainer *errors_log = NULL) const
208  {
209  // compare point and attributes
210  bool p_equal = m_point.isequalto(
211  other.m_point, geom_threshold, relative_thresholds, errors_log);
212  bool v_equal = arevectorequal(m_attributes,
213  other.m_attributes,
214  attr_threshold,
215  relative_thresholds,
216  errors_log);
217  return (p_equal && v_equal);
218  }
219 
220  // compare for exact equality
221  bool operator==(const Vertex &other) const
222  {
223  // compare point and attributes
224  return (m_point == other.m_point) && (m_attributes == other.m_attributes);
225  }
226 
227  Point m_point; // vertex coordinates
228  std::vector< FloatT > m_attributes;
229 };
230 
231 inline
232 std::ostream &
233 operator<<(std::ostream &os, const Vertex &v)
234 {
235  // write obj to stream
236  os << '[';
237  os << v.m_point;
238  for(FloatT a : v.m_attributes)
239  os << ' ' << a;
240  os << ']';
241 
242  return os;
243 }
244 
245 //------------------------------------------------------------------------------
246 
247 class Face
248 {
249 public:
250  Face(const std::deque< Vertex > &vertices,
251  const std::vector< FloatT > &attributes)
252  {
254  m_attributes = attributes;
255 
256  // rotate face vertices until the lowest point comes first
257  // example:
258  // 2 3 1 1 4
259  // 4 2 3 1 1
260  // 1 4 2 3 1
261  // 1 1 4 2 3
262  // note: the points coordinates are used, not the points indices ;
263  // if there are several lowest points in the face, use the
264  // next point after the lowest to discriminate.
265 
266  auto min_vx_it = std::min_element(
267  m_vertices.begin(), m_vertices.end()); // points to the 1st min
268 
269  // evaluate next min candidate
270  auto min_vx_it_candidate =
271  std::find(min_vx_it + 1, m_vertices.end(), *min_vx_it);
272  while(min_vx_it_candidate != m_vertices.end())
273  {
274  auto min_vx_it_candidate_next = next_vertex_in_face(min_vx_it_candidate);
275  auto min_vx_it_next = next_vertex_in_face(min_vx_it);
276 
277  while(*min_vx_it_candidate_next == *min_vx_it_next &&
278  min_vx_it_candidate_next != min_vx_it /*to avoid cycle*/)
279  {
280  min_vx_it_candidate_next =
281  next_vertex_in_face(min_vx_it_candidate_next);
282  min_vx_it_next = next_vertex_in_face(min_vx_it_next);
283  }
284 
285  if((*min_vx_it_candidate_next) < (*min_vx_it_next))
286  min_vx_it = min_vx_it_candidate;
287 
288  min_vx_it_candidate =
289  std::find(min_vx_it_candidate + 1, m_vertices.end(), *min_vx_it);
290  }
291 
292  // rotate vertices list until the minimal vertex comes 1st
293  std::rotate(m_vertices.begin(), min_vx_it, m_vertices.end());
294  }
295 
296  bool operator<(const Face &f) const
297  {
298  auto v = m_vertices.begin();
299  auto fv = f.m_vertices.begin();
300  for(; v != m_vertices.end() && fv != f.m_vertices.end(); ++v, ++fv)
301  {
302  if(*v < *fv)
303  return true;
304  else if(*fv < *v)
305  return false;
306  }
307 
308  // all vertices are equal
309  if(m_vertices.size() < f.m_vertices.size())
310  return true;
311  else if(m_vertices.size() > f.m_vertices.size())
312  return false;
313 
314  return false; // faces are equal
315  }
316 
317  // compare for strict equality
318  bool operator==(const Face &f) const
319  {
320  // compare vertices
321  if(m_vertices.size() != f.m_vertices.size())
322  return false;
323  auto v = m_vertices.begin();
324  auto fv = f.m_vertices.begin();
325  for(; v != m_vertices.end() && fv != f.m_vertices.end(); ++v, ++fv)
326  {
327  if(!(*v == *fv))
328  return false;
329  }
330 
331  // compare attributes
332  if(m_attributes.size() != f.m_attributes.size())
333  return false;
334  auto a = m_attributes.begin();
335  auto fa = f.m_attributes.begin();
336  for(; a != m_attributes.end() && fa != f.m_attributes.end(); ++a, ++fa)
337  {
338  if(!(*a == *fa))
339  return false;
340  }
341 
342  return true;
343  }
344 
345  // compare for equality, a numerical difference is allowed
346  bool isequalto(const Face &f,
347  FloatT geom_threshold,
348  FloatT attr_threshold,
349  bool relative_thresholds,
350  ErrorContainer *errors_log = NULL) const
351  {
352  // compare vertices
353  if(m_vertices.size() != f.m_vertices.size())
354  {
355  std::cout << "Topological difference detected in face (not the same "
356  "number of vertices). Skip face comparison."
357  << std::endl;
358  return false;
359  }
360 
361  auto v = m_vertices.begin();
362  auto fv = f.m_vertices.begin();
363  for(; v != m_vertices.end() && fv != f.m_vertices.end(); ++v, ++fv)
364  {
365  if(!(v->isequalto(*fv,
366  geom_threshold,
367  attr_threshold,
368  relative_thresholds,
369  errors_log)))
370  return false;
371  }
372 
373  // compare face attributes
375  f.m_attributes,
376  attr_threshold,
377  relative_thresholds,
378  errors_log))
379  return false;
380 
381  return true;
382  }
383 
384  // return the next vertex of one vertex in face description
385  std::deque< Vertex >::iterator
386  next_vertex_in_face(std::deque< Vertex >::iterator v_it)
387  {
388  // if vIt is at the end of the face vertices list,
389  // then next vertex is the first vertex in face vertices list
390  auto v_next_it = v_it + 1;
391  if(v_next_it == m_vertices.end())
392  v_next_it = m_vertices.begin();
393 
394  return v_next_it;
395  }
396 
397  std::deque< Vertex > m_vertices; // face vertices
398  std::vector< FloatT > m_attributes; // face attributes
399 };
400 
401 inline
402 std::ostream &
403 operator<<(std::ostream &os, const Face &p)
404 {
405  // write obj to stream
406  auto v = p.m_vertices.begin();
407  os << *v;
408  ++v;
409  for(; v != p.m_vertices.end(); ++v)
410  os << '-' << *v;
411 
412  return os;
413 }
414 
415 //------------------------------------------------------------------------------
416 
417 /*
418  * A mesh, composed of vertices and faces.
419  */
420 class Mesh
421 {
422 public:
423  void load(std::ifstream &file, int vertices_nbr, int faces_nbr);
424  void display(void);
425 #if 0 // replaced by isequalto
426  bool operator==(const Mesh& m) const;
427 #endif
428  bool isequalto(const Mesh &other,
429  FloatT geom_threshold,
430  FloatT attr_threshold,
431  bool relative_thresholds,
432  ErrorContainer *errors_log = NULL);
433 
434 protected:
437  std::multiset< Vertex > m_vertices; // automatically sorted
438  std::multiset< Face > m_faces; // automatically sorted
439 };
440 
441 inline
442 void
443 Mesh::load(std::ifstream &file, int vertices_nbr, int faces_nbr)
444 {
445  m_verticesNbr = vertices_nbr;
446  m_facesNbr = faces_nbr;
447 
448  m_vertices.clear();
449  m_faces.clear();
450  std::string line;
451 
452  // load vertices
453  std::vector< Vertex > vtmp; // to later retrieve vertex by index
454  for(int i = 0; i < m_verticesNbr; i++)
455  {
456  line = get_next_line(file);
457  size_t found = line.find_first_not_of(" \t");
458  if(found != std::string::npos)
459  {
460  if(line[found] == '#')
461  continue;
462  }
463  FloatT x, y, z;
464  std::stringstream strline(line);
465  strline >> x >> y >> z;
466  Point point(x, y, z);
467 
468  // optional vertex color or other vertex attribute
469  std::vector< FloatT > vertex_attributes;
470  FloatT value;
471  while(strline >> value)
472  {
473  vertex_attributes.push_back(value);
474  }
475 
476  Vertex v(point, vertex_attributes);
477  vtmp.push_back(v);
478  m_vertices.insert(v);
479  }
480 
481  // check if some vertices are duplicated
482 #if 0
483  //TODO-elo turned off because break a number of existing CI tests
484  std::set<Vertex> unique_vertices(m_vertices.begin(), m_vertices.end());
485  if( unique_vertices.size() != m_vertices.size() )
486  throw std::runtime_error("Some vertices are duplicated (same coordinates and attributes). Can't reliably compare the meshes. Aborting.");
487 #endif
488 
489  // load faces
490  for(int i = 0; i < m_facesNbr; i++)
491  {
492  line = get_next_line(file);
493  std::stringstream strline(line);
494 
495  int v_nbr;
496  strline >> v_nbr;
497 
498  std::deque< Vertex > face;
499  for(int j = 0; j < v_nbr; j++)
500  {
501  int v_id;
502  strline >> v_id;
503  face.push_back(vtmp[v_id]);
504  }
505 
506  // optional face color (or other face attribute)
507  std::vector< FloatT > face_attributes;
508  FloatT value;
509  while(strline >> value)
510  {
511  face_attributes.push_back(value);
512  }
513 
514  m_faces.insert(Face(face, face_attributes));
515  }
516 }
517 
518 inline
519 void
521 {
522  // display points list
523  for(auto v = m_vertices.begin(); v != m_vertices.end(); ++v)
524  std::cout << ' ' << *v << '\n';
525 
526  // display faces list
527  for(auto f = m_faces.begin(); f != m_faces.end(); ++f)
528  std::cout << ' ' << *f << '\n';
529 }
530 
531 #if 0 // replaced by isequalto
532 bool Mesh::operator==(const Mesh& m) const
533 {
534  // check vertices and faces numbers
535  if( m_vertices.size() != m.m_vertices.size() )
536  return false;
537 
538  if( m_faces.size() != m.m_faces.size() )
539  return false;
540 
541  // check vertices equality
542  auto v = m_vertices.begin();
543  auto mv = m.m_vertices.begin();
544  for(; v != m_vertices.end() && mv != m.m_vertices.end(); ++v, ++mv)
545  {
546  if( ! (*v == *mv) )
547  {
548  std::cout << "Difference found between vertices:\n";
549  std::cout << "(a) " << *v << '\n';
550  std::cout << "(b) " << *mv << '\n';
551 
552  return false;
553  }
554  }
555 
556  // check faces equality
557  auto f = m_faces.begin();
558  auto mf = m.m_faces.begin();
559  for(; f != m_faces.end() && mf != m.m_faces.end(); ++f, ++mf)
560  {
561  if( ! (*f == *mf) )
562  {
563  std::cout << "Difference found between faces:\n";
564  std::cout << "(a) " << *f << '\n';
565  std::cout << "(b) " << *mf << '\n';
566 
567  return false;
568  }
569  }
570 
571  return true;
572 }
573 #endif
574 
575 // test Mesh approximated equality
576 inline
577 bool
578 Mesh::isequalto(const Mesh &other,
579  FloatT geom_threshold,
580  FloatT attr_threshold,
581  bool relative_thresholds,
582  ErrorContainer *errors_log)
583 {
584  // check vertices and faces numbers
585  if(m_vertices.size() != other.m_vertices.size())
586  {
587  std::cout << "Topological difference detected in mesh (not the same number "
588  "of vertices). Skip mesh comparison."
589  << std::endl;
590  return false;
591  }
592 
593  if(m_faces.size() != other.m_faces.size())
594  {
595  std::cout << "Topological difference detected in mesh (not the same number "
596  "of faces). Skip mesh comparison."
597  << std::endl;
598  return false;
599  }
600 
601  bool isequal = true;
602  unsigned int vertice_error_nbr = 0;
603  unsigned int face_error_nbr = 0;
604 
605  // check vertices equality
606  auto vi = m_vertices.begin();
607  auto othervi = other.m_vertices.begin();
608  for(; vi != m_vertices.end(); ++vi, ++othervi)
609  {
610  if(!(vi->isequalto(*othervi,
611  geom_threshold,
612  attr_threshold,
613  relative_thresholds,
614  errors_log)))
615  {
616  std::cout << "Difference found between vertices:\n";
617  std::cout << " (a) " << *vi << '\n';
618  std::cout << " (b) " << *othervi << '\n';
619 
620  isequal = false;
621  vertice_error_nbr++;
622  }
623  }
624 
625  // check faces equality
626  auto f = m_faces.begin();
627  auto otherf = other.m_faces.begin();
628  for(; f != m_faces.end(); ++f, ++otherf)
629  {
630  if(!(f->isequalto(*otherf,
631  geom_threshold,
632  attr_threshold,
633  relative_thresholds,
634  errors_log)))
635  {
636  std::cout << "Difference found between faces:\n";
637  std::cout << " (a) " << *f << '\n';
638  std::cout << " (b) " << *otherf << '\n';
639 
640  isequal = false;
641  face_error_nbr++;
642  }
643  }
644 
645  if(!isequal)
646  {
647  std::cout << "Number of differences in vertices: " << vertice_error_nbr
648  << std::endl;
649  std::cout << "Number of differences in faces: " << face_error_nbr
650  << std::endl;
651  }
652 
653  return isequal;
654 }
655 
656 //------------------------------------------------------------------------------
657 
658 /*
659  * Get next line from .off file.
660  * Skip empty lines and lines beginning with '#'
661  */
662 inline
663 std::string
664 get_next_line(std::ifstream &file)
665 {
666  std::string line;
667  do
668  {
669  std::getline(file, line);
670 
671  // remove DOS end of line extra character if any
672  if((!line.empty()) && (line.back() == '\r'))
673  line.pop_back();
674  } while(line.empty() || line[0] == '#');
675 
676  return line;
677 }
678 
679 /*
680  * Compute the relative distance between two floats.
681  */
682 inline
683 FloatT
685 {
686  if(a == b)
687  return 0.0;
688 
689  FloatT mean_abs = (std::abs(a) + std::abs(b)) / 2.0f;
690  FloatT rel_dist = std::abs(a - b) / mean_abs;
691 
692  return rel_dist;
693 }
694 
695 /*
696  * Compute the absolute distance between two floats.
697  */
698 inline
699 FloatT
701 {
702  return std::abs(a - b);
703 }
704 
705 /*
706  * Compare to vectors of floats for approximated equality.
707  */
708 inline
709 bool
710 arevectorequal(const std::vector< FloatT > &v1,
711  const std::vector< FloatT > &v2,
712  FloatT attr_threshold,
713  bool relative_threshold,
714  ErrorContainer *errors_log)
715 {
716  if(v1.size() != v2.size())
717  {
718  std::cout
719  << "The two vectors don't have the same size. Skip vectors comparison."
720  << std::endl;
721  return false;
722  }
723 
724  // check vectors elements equality (approximated)
725  bool are_vectors_equal = true;
726  bool are_values_equal = true;
727  auto v1i = v1.begin();
728  auto v2i = v2.begin();
729  for(; v1i != v1.end(); ++v1i, ++v2i)
730  {
731  are_values_equal = true;
732 
733  if(attr_threshold == 0)
734  {
735  // do an exact comparison
736  if(!(*v1i == *v2i))
737  {
738  are_values_equal = false;
739  are_vectors_equal = false;
740  }
741  }
742  else if(relative_threshold)
743  {
744  // comparison with a relative threshold
745  FloatT rel_dist = relative_distance(*v1i, *v2i);
746  if(rel_dist > attr_threshold)
747  {
748  are_values_equal = false;
749  are_vectors_equal = false;
750  }
751  }
752  else
753  {
754  // comparison with an absolute threshold
755  FloatT dist = absolute_distance(*v1i, *v2i);
756  if(dist > attr_threshold)
757  {
758  are_values_equal = false;
759  are_vectors_equal = false;
760  }
761  }
762 
763  if(!are_values_equal && errors_log)
764  {
765  // log errors for future statistics
766  errors_log->insert(std::make_pair(*v1i, *v2i));
767  }
768  }
769 
770  return are_vectors_equal;
771 }
772 
773 //------------------------------------------------------------------------------
774 
775 } // namespace are_meshes_identical
776 
777 //------------------------------------------------------------------------------
778 
779 inline
780 bool
781 are_meshes_equal(std::string filename_a,
782  std::string filename_b,
783  bool verbose,
784  FloatT geom_threshold,
785  FloatT attr_threshold,
786  bool relative_thresholds)
787 {
788  std::ifstream file_a(filename_a);
789  if(!file_a)
790  {
791  std::cout << "Unable to read first file." << filename_a << std::endl;
792  return false;
793  }
794 
795  std::ifstream file_b(filename_b);
796  if(!file_b)
797  {
798  std::cout << "Unable to read second file " << filename_b << std::endl;
799  return false;
800  }
801 
802  std::string line_a;
803  std::string line_b;
804 
805  // check that files are in OFF format
806 
807  line_a = are_meshes_identical::get_next_line(file_a);
808  if(line_a != "OFF" && line_a != "COFF")
809  {
810  std::cout << filename_a << " is not in OFF format." << std::endl;
811  return false;
812  }
813 
814  line_b = are_meshes_identical::get_next_line(file_b);
815  if(line_b != "OFF" && line_b != "COFF")
816  {
817  std::cout << filename_b << " is not in OFF format." << std::endl;
818  return false;
819  }
820 
821  // check meshes sizes
822 
823  int vertices_nbr_a, faces_nbr_a, edges_nbr_a;
824  std::stringstream(are_meshes_identical::get_next_line(file_a))
825  >> vertices_nbr_a >> faces_nbr_a >> edges_nbr_a;
826  int vertices_nbr_b, faces_nbr_b, edges_nbr_b;
827  std::stringstream(are_meshes_identical::get_next_line(file_b))
828  >> vertices_nbr_b >> faces_nbr_b >> edges_nbr_b;
829 
830  if(vertices_nbr_a != vertices_nbr_b ||
831  faces_nbr_a != faces_nbr_b /*||
832  edgesNbrA != edgesNbrB*/) // number of edges is not
833  // always correct in .off
834  // files!
835  {
836  std::cout << "Meshes do NOT have the same size:" << std::endl;
837  std::cout << " - " << filename_a << " has " << vertices_nbr_a
838  << " vertices, " << faces_nbr_a << " faces, and " << edges_nbr_a
839  << " edges" << std::endl;
840  std::cout << " - " << filename_b << " has " << vertices_nbr_b
841  << " vertices, " << faces_nbr_b << " faces, and " << edges_nbr_b
842  << " edges" << std::endl;
843  return false;
844  }
845 
846  // load meshes
847 
848  are_meshes_identical::Mesh mesh_a, mesh_b;
849  mesh_a.load(file_a, vertices_nbr_a, faces_nbr_a);
850  mesh_b.load(file_b, vertices_nbr_b, faces_nbr_b);
851 
852  if(verbose)
853  {
854  std::cout << "Mesh A =\n";
855  mesh_a.display();
856  std::cout << '\n';
857  std::cout << "Mesh B =\n";
858  mesh_b.display();
859  std::cout << '\n';
860  }
861 
862  // compare meshes
864  bool isequal = mesh_a.isequalto(
865  mesh_b, geom_threshold, attr_threshold, relative_thresholds, &errors_log);
866 
867  if(!isequal)
868  {
869  // display information on errors
870 
871  std::vector< FloatT > errors;
872  if(relative_thresholds)
873  {
874  for(auto pair : errors_log)
875  errors.push_back(
876  are_meshes_identical::relative_distance(pair.first, pair.second));
877  }
878  else
879  {
880  for(auto pair : errors_log)
881  errors.push_back(
882  are_meshes_identical::absolute_distance(pair.first, pair.second));
883  }
884 
885  auto minmax = std::minmax_element(errors.begin(), errors.end());
886  FloatT min = *(minmax.first);
887  FloatT max = *(minmax.second);
888  FloatT mean =
889  std::accumulate(errors.begin(), errors.end(), 0.0f) / errors.size();
890 
891  std::cout << "Number of effective numeric errors: " << errors.size()
892  << std::endl;
893  std::cout << "Numeric error min = " << min << std::endl;
894  std::cout << "Numeric error max = " << max << std::endl;
895  std::cout << "Numeric error mean = " << mean << std::endl;
896  if(relative_thresholds)
897  std::cout << "Mode: relative error" << std::endl;
898  else
899  std::cout << "Mode: absolute error" << std::endl;
900  }
901 
902  return isequal;
903 }
904 
905 
906 inline
907 bool
908 are_meshes_equal(std::string filename_a,
909  std::string filename_b,
910  bool verbose,
911  FloatT threshold,
912  bool relative_threshold)
913 {
914  return are_meshes_equal(filename_a,
915  filename_b,
916  verbose,
917  threshold,
918  threshold,
919  relative_threshold);
920 }
921 
922 
923 inline
924 bool
925 are_meshes_equal(std::string filename_a, std::string filename_b, bool verbose)
926 {
927  return are_meshes_equal(filename_a, filename_b, verbose, 0, 0, false);
928 }
are_meshes_identical::operator<<
std::ostream & operator<<(std::ostream &os, const Point &p)
Definition: utils_are_meshes_identical.inl:166
are_meshes_identical::Vertex
Definition: utils_are_meshes_identical.inl:176
FEVV::DataStructures::AIF::vertices
std::pair< typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::vertex_iterator, typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::vertex_iterator > vertices(const FEVV::DataStructures::AIF::AIFMesh &sm)
Returns the iterator range of the vertices of the mesh.
Definition: Graph_traits_aif.h:172
are_meshes_identical::Vertex::Vertex
Vertex(const Point &point, const std::vector< FloatT > &attributes)
Definition: utils_are_meshes_identical.inl:178
are_meshes_identical::Vertex::m_attributes
std::vector< FloatT > m_attributes
Definition: utils_are_meshes_identical.inl:228
FloatT
float FloatT
Definition: utils_are_meshes_identical.hpp:16
are_meshes_identical::Point::Point
Point(FloatT x=0, FloatT y=0, FloatT z=0)
Definition: utils_are_meshes_identical.inl:62
are_meshes_identical::Mesh::load
void load(std::ifstream &file, int vertices_nbr, int faces_nbr)
Definition: utils_are_meshes_identical.inl:443
are_meshes_identical::Face::operator==
bool operator==(const Face &f) const
Definition: utils_are_meshes_identical.inl:318
are_meshes_equal
bool are_meshes_equal(std::string filename_a, std::string filename_b, bool verbose, FloatT geom_threshold, FloatT attr_threshold, bool relative_thresholds)
Definition: utils_are_meshes_identical.inl:781
FEVV::Math::Vector::Stats::mean
static ElementType mean(const ElementType v[DIM])
Definition: MatrixOperations.hpp:133
are_meshes_identical::arevectorequal
bool arevectorequal(const std::vector< FloatT > &v1, const std::vector< FloatT > &v2, FloatT attr_threshold, bool relative_threshold, ErrorContainer *errors_log)
Definition: utils_are_meshes_identical.inl:710
are_meshes_identical::Point::m_x
FloatT m_x
Definition: utils_are_meshes_identical.inl:161
are_meshes_identical::Point::m_y
FloatT m_y
Definition: utils_are_meshes_identical.inl:161
are_meshes_identical
Definition: utils_are_meshes_identical.inl:24
are_meshes_identical::Mesh::m_facesNbr
int m_facesNbr
Definition: utils_are_meshes_identical.inl:436
are_meshes_identical::Vertex::m_point
Point m_point
Definition: utils_are_meshes_identical.inl:227
are_meshes_identical::Face
Definition: utils_are_meshes_identical.inl:248
are_meshes_identical::Face::operator<
bool operator<(const Face &f) const
Definition: utils_are_meshes_identical.inl:296
are_meshes_identical::Point::operator<
bool operator<(const Point &p) const
Definition: utils_are_meshes_identical.inl:69
are_meshes_identical::Vertex::operator=
Vertex & operator=(const Vertex &other)
Definition: utils_are_meshes_identical.inl:184
are_meshes_identical::Point
Definition: utils_are_meshes_identical.inl:60
are_meshes_identical::Face::next_vertex_in_face
std::deque< Vertex >::iterator next_vertex_in_face(std::deque< Vertex >::iterator v_it)
Definition: utils_are_meshes_identical.inl:386
are_meshes_identical::Point::m_z
FloatT m_z
Definition: utils_are_meshes_identical.inl:161
are_meshes_identical::Face::isequalto
bool isequalto(const Face &f, FloatT geom_threshold, FloatT attr_threshold, bool relative_thresholds, ErrorContainer *errors_log=NULL) const
Definition: utils_are_meshes_identical.inl:346
are_meshes_identical::Point::isequalto
bool isequalto(const Point &p, FloatT geom_threshold, bool relative_threshold, ErrorContainer *errors_log=NULL) const
Definition: utils_are_meshes_identical.inl:90
are_meshes_identical::ErrorContainer
std::set< std::pair< FloatT, FloatT > > ErrorContainer
Definition: utils_are_meshes_identical.inl:28
are_meshes_identical::get_next_line
std::string get_next_line(std::ifstream &file)
Definition: utils_are_meshes_identical.inl:664
are_meshes_identical::Mesh::m_faces
std::multiset< Face > m_faces
Definition: utils_are_meshes_identical.inl:438
are_meshes_identical::Vertex::operator==
bool operator==(const Vertex &other) const
Definition: utils_are_meshes_identical.inl:221
are_meshes_identical::Mesh::display
void display(void)
Definition: utils_are_meshes_identical.inl:520
are_meshes_identical::relative_distance
FloatT relative_distance(FloatT a, FloatT b)
Definition: utils_are_meshes_identical.inl:684
are_meshes_identical::Mesh::m_verticesNbr
int m_verticesNbr
Definition: utils_are_meshes_identical.inl:435
are_meshes_identical::Vertex::isequalto
bool isequalto(const Vertex &other, FloatT geom_threshold, FloatT attr_threshold, bool relative_thresholds, ErrorContainer *errors_log=NULL) const
Definition: utils_are_meshes_identical.inl:203
are_meshes_identical::Vertex::operator<
bool operator<(const Vertex &other) const
Definition: utils_are_meshes_identical.inl:192
are_meshes_identical::Face::m_vertices
std::deque< Vertex > m_vertices
Definition: utils_are_meshes_identical.inl:397
are_meshes_identical::Mesh::m_vertices
std::multiset< Vertex > m_vertices
Definition: utils_are_meshes_identical.inl:437
FEVV::DataStructures::AIF::face
boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::face_descriptor face(typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::halfedge_descriptor h, const FEVV::DataStructures::AIF::AIFMesh &)
Returns the face incident to halfedge h.
Definition: Graph_traits_aif.h:664
are_meshes_identical::Face::m_attributes
std::vector< FloatT > m_attributes
Definition: utils_are_meshes_identical.inl:398
are_meshes_identical::Mesh
Definition: utils_are_meshes_identical.inl:421
are_meshes_identical::Face::Face
Face(const std::deque< Vertex > &vertices, const std::vector< FloatT > &attributes)
Definition: utils_are_meshes_identical.inl:250
are_meshes_identical::Mesh::isequalto
bool isequalto(const Mesh &other, FloatT geom_threshold, FloatT attr_threshold, bool relative_thresholds, ErrorContainer *errors_log=NULL)
Definition: utils_are_meshes_identical.inl:578
are_meshes_identical::Point::operator==
bool operator==(const Point &p) const
Definition: utils_are_meshes_identical.inl:154
are_meshes_identical::absolute_distance
FloatT absolute_distance(FloatT a, FloatT b)
Definition: utils_are_meshes_identical.inl:700