1 /****************************************************************************
2 * VCGLib                                                            o o     *
3 * Visual and Computer Graphics Library                            o     o   *
4 *                                                                _   O  _   *
5 * Copyright(C) 2004-2016                                           \/)\/    *
6 * Visual Computing Lab                                            /\/|      *
7 * ISTI - Italian National Research Council                           |      *
8 *                                                                    \      *
9 * All rights reserved.                                                      *
10 *                                                                           *
11 * This program is free software; you can redistribute it and/or modify      *
12 * it under the terms of the GNU General Public License as published by      *
13 * the Free Software Foundation; either version 2 of the License, or         *
14 * (at your option) any later version.                                       *
15 *                                                                           *
16 * This program is distributed in the hope that it will be useful,           *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
19 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)          *
20 * for more details.                                                         *
21 *                                                                           *
22 ****************************************************************************/
23 
24 // standard libraries
25 #include <time.h>
26 #include <vcg/math/histogram.h>
27 #include <vcg/complex/complex.h>
28 #include <wrap/io_trimesh/import.h>
29 #include <wrap/io_trimesh/export.h>
30 #include <vcg/simplex/face/component_ep.h>
31 #include <vcg/complex/algorithms/update/component_ep.h>
32 #include <vcg/complex/algorithms/update/bounding.h>
33 #include "sampling.h"
34 
35 using namespace std;
36 // project definitions.
37 // error messages
38 
39 #define MSG_ERR_MESH_LOAD               "error loading the input meshes.\n"
40 #define MSG_ERR_INVALID_OPTION          "unable to parse option '%s'\n"
41 #define MSG_ERR_FILE_OPEN               "unable to open the output file.'n"
42 #define MSG_ERR_UNKNOWN_FORMAT          "unknown file format '%s'.\n"
43 
44 // global constants
45 #define NO_SAMPLES_PER_FACE             10
46 #define N_SAMPLES_EDGE_TO_FACE_RATIO    0.1
47 #define BBOX_FACTOR                     0.1
48 #define INFLATE_PERCENTAGE			    0.02
49 #define MIN_SIZE					    125		/* 125 = 5^3 */
50 #define N_HIST_BINS                     256
51 #define PRINT_EVERY_N_ELEMENTS          1000
52 
53 
54 class CFace;
55 class CVertex;
56 struct UsedTypes:public vcg::UsedTypes< vcg::Use<CFace>::AsFaceType, vcg::Use<CVertex>::AsVertexType>{};
57 class CVertex   : public vcg::Vertex<UsedTypes,vcg::vertex::Coord3d,vcg::vertex::Qualityf,vcg::vertex::Normal3d,vcg::vertex::Color4b,vcg::vertex::BitFlags> {};
58 class CFace     : public vcg::Face< UsedTypes,vcg::face::VertexRef, vcg::face::Normal3d, vcg::face::EdgePlane,vcg::face::Color4b,vcg::face::Mark,vcg::face::BitFlags> {};
59 class CMesh     : public vcg::tri::TriMesh< std::vector<CVertex>, std::vector<CFace> > {};
60 
61 
62 // -----------------------------------------------------------------------------------------------
63 
64 using namespace vcg;
65 
66 
67 ////////////////// Command line Flags and parameters
68 bool NumberOfSamples                = false;
69 bool SamplesPerAreaUnit             = false;
70 bool CleaningFlag=false;
71 // -----------------------------------------------------------------------------------------------
72 
Usage()73 void Usage()
74 {
75   printf("\nUsage:  "\
76                                         "metro file1 file2 [opt]\n"\
77                                         "Where opt can be:\n"\
78                                         "  -v         disable vertex sampling\n"\
79                                         "  -e         disable edge sampling\n"\
80                                         "  -f         disable face sampling\n"\
81                                         "  -u         ignore unreferred vertices\n"\
82                                         "  -sx        set the face sampling mode\n"\
83                                         "             where x can be:\n"\
84                                         "              -s0  montecarlo sampling\n"\
85                                         "              -s1  subdivision sampling\n"\
86                                         "              -s2  similar triangles sampling (Default)\n"\
87                                         "  -n#        set the required number of samples (overrides -A)\n"\
88                                         "  -a#        set the required number of samples per area unit (overrides -N)\n"\
89                                         "  -c         save a mesh with error as per-vertex colour and quality\n"\
90                                         "  -C # #     Set the min/max values used for color mapping\n"\
91                                         "  -L         Remove duplicated and unreferenced vertices before processing\n"\
92                                         "  -h         write files with histograms of error distribution\n"\
93                                         "  -G         Use a static Uniform Grid as Search Structure (default)\n"\
94 																				"  -O         Use an octree as a Search Structure\n"\
95                                         "  -A         Use an AxisAligned Bounding Box Tree as Search Structure\n"\
96                                         "  -H         Use an Hashed Uniform Grid as Search Structure\n"\
97                                         "\n"
98                                         "Default options are to sample vertexes, edge and faces by taking \n"
99                                         "a number of samples that is approx. 10x the face number.\n"
100                                         );
101   exit(-1);
102 }
103 
104 
105 // simple aux function that compute the name for the file containing the stored computations
SaveFileName(const std::string & filename)106 std::string SaveFileName(const std::string &filename)
107 {
108  int pos=filename.find_last_of('.',filename.length());
109  std::string fileout=filename.substr(0,pos)+"_metro.ply";
110  return fileout;
111 }
112 
113 
114 // Open Mesh
OpenMesh(const char * filename,CMesh & m)115 void OpenMesh(const char *filename, CMesh &m)
116 {
117   int err = tri::io::Importer<CMesh>::Open(m,filename);
118   if(err) {
119       printf("Error in reading %s: '%s'\n",filename,tri::io::Importer<CMesh>::ErrorMsg(err));
120       if(tri::io::Importer<CMesh>::ErrorCritical(err)) exit(-1);
121     }
122   printf("read mesh `%s'\n", filename);
123   if(CleaningFlag){
124       int dup = tri::Clean<CMesh>::RemoveDuplicateVertex(m);
125       int unref =  tri::Clean<CMesh>::RemoveUnreferencedVertex(m);
126       printf("Removed %i duplicate and %i unreferenced vertices from mesh %s\n",dup,unref,filename);
127   }
128 }
129 
130 
main(int argc,char ** argv)131 int main(int argc, char**argv)
132 {
133     CMesh                 S1, S2;
134     float                ColorMin=0, ColorMax=0;
135     double                dist1_max, dist2_max;
136     unsigned long         n_samples_target, elapsed_time;
137     double								n_samples_per_area_unit;
138     int                   flags;
139 
140     // print program info
141     printf("-------------------------------\n"
142            "         Metro V.4.07 \n"
143            "     http://vcg.isti.cnr.it\n"
144            "   release date: " __DATE__ "\n"
145            "-------------------------------\n\n");
146 
147     if(argc <= 2)    Usage();
148     // default parameters
149     flags = SamplingFlags::VERTEX_SAMPLING |
150           SamplingFlags::EDGE_SAMPLING |
151           SamplingFlags::FACE_SAMPLING |
152           SamplingFlags::SIMILAR_SAMPLING;
153 
154     // parse command line.
155 	  for(int i=3; i < argc;)
156     {
157       if(argv[i][0]=='-')
158         switch(argv[i][1])
159       {
160         case 'h' : flags |= SamplingFlags::HIST; break;
161         case 'v' : flags &= ~SamplingFlags::VERTEX_SAMPLING; break;
162         case 'e' : flags &= ~SamplingFlags::EDGE_SAMPLING; break;
163         case 'f' : flags &= ~SamplingFlags::FACE_SAMPLING; break;
164         case 'u' : flags |= SamplingFlags::INCLUDE_UNREFERENCED_VERTICES; break;
165         case 's'   :
166           switch(argv[i][2])
167           {
168             case '0':  flags = (flags | SamplingFlags::MONTECARLO_SAMPLING  ) & (~ SamplingFlags::NO_SAMPLING );break;
169             case '1':  flags = (flags | SamplingFlags::SUBDIVISION_SAMPLING ) & (~ SamplingFlags::NO_SAMPLING );break;
170             case '2':  flags = (flags | SamplingFlags::SIMILAR_SAMPLING     ) & (~ SamplingFlags::NO_SAMPLING );break;
171             default  :  printf(MSG_ERR_INVALID_OPTION, argv[i]);
172               exit(0);
173           }
174           break;
175         case 'n':  NumberOfSamples       = true;     n_samples_target        = (unsigned long) atoi(&(argv[i][2]));          break;
176         case 'a':  SamplesPerAreaUnit    = true;     n_samples_per_area_unit = (unsigned long) atoi(&(argv[i][2])); break;
177         case 'c':  flags |= SamplingFlags::SAVE_ERROR;   break;
178         case 'L':  CleaningFlag=true; break;
179         case 'C':  ColorMin=float(atof(argv[i+1])); ColorMax=float(atof(argv[i+2])); i+=2; break;
180         case 'A':  flags |= SamplingFlags::USE_AABB_TREE;   printf("Using AABB Tree as search structure\n");           break;
181         case 'G':  flags |= SamplingFlags::USE_STATIC_GRID; printf("Using static uniform grid as search structure\n"); break;
182         case 'H':  flags |= SamplingFlags::USE_HASH_GRID;   printf("Using hashed uniform grid as search structure\n"); break;
183 				case 'O':  flags |= SamplingFlags::USE_OCTREE;      printf("Using octree as search structure\n");              break;
184         default  :  printf(MSG_ERR_INVALID_OPTION, argv[i]);
185           exit(0);
186       }
187       i++;
188     }
189 
190 		if(!(flags & SamplingFlags::USE_HASH_GRID) && !(flags & SamplingFlags::USE_AABB_TREE) && !(flags & SamplingFlags::USE_OCTREE))
191        flags |= SamplingFlags::USE_STATIC_GRID;
192 
193     // load input meshes.
194     OpenMesh(argv[1],S1);
195     OpenMesh(argv[2],S2);
196 
197     string S1NewName=SaveFileName(argv[1]);
198     string S2NewName=SaveFileName(argv[2]);
199 
200     if(!NumberOfSamples && !SamplesPerAreaUnit)
201     {
202         NumberOfSamples = true;
203         n_samples_target = 10 * max(S1.fn,S2.fn);// take 10 samples per face
204     }
205 
206     // compute face information
207         tri::UpdateComponentEP<CMesh>::Set(S1);
208         tri::UpdateComponentEP<CMesh>::Set(S2);
209 
210 	// set bounding boxes for S1 and S2
211 		tri::UpdateBounding<CMesh>::Box(S1);
212 		tri::UpdateBounding<CMesh>::Box(S2);
213 
214     // set Bounding Box.
215 		Box3<CMesh::ScalarType>    bbox, tmp_bbox_M1=S1.bbox, tmp_bbox_M2=S2.bbox;
216     bbox.Add(S1.bbox);
217     bbox.Add(S2.bbox);
218 		bbox.Offset(bbox.Diag()*0.02);
219 	  S1.bbox = bbox;
220 	  S2.bbox = bbox;
221 
222     // initialize time info.
223     int t0=clock();
224 
225     Sampling<CMesh> ForwardSampling(S1,S2);
226     Sampling<CMesh> BackwardSampling(S2,S1);
227 
228     // print mesh info.
229     printf("Mesh info:\n");
230     printf(" M1: '%s'\n\tvertices  %7i\n\tfaces     %7i\n\tarea      %12.4f\n", argv[1], S1.vn, S1.fn, ForwardSampling.GetArea());
231     printf("\tbbox (%7.4f %7.4f %7.4f)-(%7.4f %7.4f %7.4f)\n", tmp_bbox_M1.min[0], tmp_bbox_M1.min[1], tmp_bbox_M1.min[2], tmp_bbox_M1.max[0], tmp_bbox_M1.max[1], tmp_bbox_M1.max[2]);
232     printf("\tbbox diagonal %f\n", (float)tmp_bbox_M1.Diag());
233     printf(" M2: '%s'\n\tvertices  %7i\n\tfaces     %7i\n\tarea      %12.4f\n", argv[2], S2.vn, S2.fn, BackwardSampling.GetArea());
234     printf("\tbbox (%7.4f %7.4f %7.4f)-(%7.4f %7.4f %7.4f)\n", tmp_bbox_M2.min[0], tmp_bbox_M2.min[1], tmp_bbox_M2.min[2], tmp_bbox_M2.max[0], tmp_bbox_M2.max[1], tmp_bbox_M2.max[2]);
235     printf("\tbbox diagonal %f\n", (float)tmp_bbox_M2.Diag());
236 
237     // Forward distance.
238     printf("\nForward distance (M1 -> M2):\n");
239     ForwardSampling.SetFlags(flags);
240     if(NumberOfSamples)
241     {
242         ForwardSampling.SetSamplesTarget(n_samples_target);
243         n_samples_per_area_unit = ForwardSampling.GetNSamplesPerAreaUnit();
244     }
245     else
246     {
247         ForwardSampling.SetSamplesPerAreaUnit(n_samples_per_area_unit);
248         n_samples_target = ForwardSampling.GetNSamplesTarget();
249     }
250     printf("target # samples      : %lu\ntarget # samples/area : %f\n", n_samples_target, n_samples_per_area_unit);
251     ForwardSampling.Hausdorff();
252     dist1_max  = ForwardSampling.GetDistMax();
253     printf("\ndistances:\n  max  : %f (%f  wrt bounding box diagonal)\n", (float)dist1_max, (float)dist1_max/bbox.Diag());
254     printf("  mean : %f\n", ForwardSampling.GetDistMean());
255     printf("  RMS  : %f\n", ForwardSampling.GetDistRMS());
256     printf("# vertex samples %9lu\n", ForwardSampling.GetNVertexSamples());
257     printf("# edge samples   %9lu\n", ForwardSampling.GetNEdgeSamples());
258     printf("# area samples   %9lu\n", ForwardSampling.GetNAreaSamples());
259     printf("# total samples  %9lu\n", ForwardSampling.GetNSamples());
260     printf("# samples per area unit: %f\n\n", ForwardSampling.GetNSamplesPerAreaUnit());
261 
262     // Backward distance.
263     printf("\nBackward distance (M2 -> M1):\n");
264     BackwardSampling.SetFlags(flags);
265     if(NumberOfSamples)
266     {
267         BackwardSampling.SetSamplesTarget(n_samples_target);
268         n_samples_per_area_unit = BackwardSampling.GetNSamplesPerAreaUnit();
269     }
270     else
271     {
272         BackwardSampling.SetSamplesPerAreaUnit(n_samples_per_area_unit);
273         n_samples_target = BackwardSampling.GetNSamplesTarget();
274     }
275     printf("target # samples      : %lu\ntarget # samples/area : %f\n", n_samples_target, n_samples_per_area_unit);
276     BackwardSampling.Hausdorff();
277     dist2_max  = BackwardSampling.GetDistMax();
278     printf("\ndistances:\n  max  : %f (%f  wrt bounding box diagonal)\n", (float)dist2_max, (float)dist2_max/bbox.Diag());
279     printf("  mean : %f\n", BackwardSampling.GetDistMean());
280     printf("  RMS  : %f\n", BackwardSampling.GetDistRMS());
281     printf("# vertex samples %9lu\n", BackwardSampling.GetNVertexSamples());
282     printf("# edge samples   %9lu\n", BackwardSampling.GetNEdgeSamples());
283     printf("# area samples   %9lu\n", BackwardSampling.GetNAreaSamples());
284     printf("# total samples  %9lu\n", BackwardSampling.GetNSamples());
285     printf("# samples per area unit: %f\n\n", BackwardSampling.GetNSamplesPerAreaUnit());
286 
287     // compute time info.
288     elapsed_time = clock() - t0;
289     int n_total_sample=ForwardSampling.GetNSamples()+BackwardSampling.GetNSamples();
290     double mesh_dist_max  = max(dist1_max , dist2_max);
291 
292     printf("\nHausdorff distance: %f (%f  wrt bounding box diagonal)\n",(float)mesh_dist_max,(float)mesh_dist_max/bbox.Diag());
293     printf("  Computation time  : %d ms\n",(int)(1000.0*elapsed_time/CLOCKS_PER_SEC));
294     printf("  # samples/second  : %f\n\n", (float)n_total_sample/((float)elapsed_time/CLOCKS_PER_SEC));
295 
296     // save error files.
297     if(flags & SamplingFlags::SAVE_ERROR)
298     {
299       int saveMask = vcg::tri::io::Mask::IOM_VERTCOLOR | vcg::tri::io::Mask::IOM_VERTQUALITY /* | vcg::ply::PLYMask::PM_VERTQUALITY*/ ;
300       //p.mask|=vcg::ply::PLYMask::PM_VERTCOLOR|vcg::ply::PLYMask::PM_VERTQUALITY;
301       if(ColorMax!=0 || ColorMin != 0){
302         vcg::tri::UpdateColor<CMesh>::PerVertexQualityRamp(S1,ColorMin,ColorMax);
303         vcg::tri::UpdateColor<CMesh>::PerVertexQualityRamp(S2,ColorMin,ColorMax);
304       }
305       tri::io::ExporterPLY<CMesh>::Save( S1,S1NewName.c_str(),saveMask);
306       tri::io::ExporterPLY<CMesh>::Save( S2,S2NewName.c_str(),saveMask);
307     }
308 
309     // save error files.
310     if(flags & SamplingFlags::HIST)
311     {
312       ForwardSampling.GetHist().FileWrite("forward_result.csv");
313       BackwardSampling.GetHist().FileWrite("backward_result.csv");
314     }
315    return 0;
316 }
317 
318 // -----------------------------------------------------------------------------------------------
319