1 /*
2  *  Copyright (c) 2012-2014, Bruno Levy
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *
8  *  * Redistributions of source code must retain the above copyright notice,
9  *  this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright notice,
11  *  this list of conditions and the following disclaimer in the documentation
12  *  and/or other materials provided with the distribution.
13  *  * Neither the name of the ALICE Project-Team nor the names of its
14  *  contributors may be used to endorse or promote products derived from this
15  *  software without specific prior written permission.
16  *
17  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  *  POSSIBILITY OF SUCH DAMAGE.
28  *
29  *  If you modify this software, you should include a notice giving the
30  *  name of the person performing the modification, the date of modification,
31  *  and the reason for such modification.
32  *
33  *  Contact: Bruno Levy
34  *
35  *     Bruno.Levy@inria.fr
36  *     http://www.loria.fr/~levy
37  *
38  *     ALICE Project
39  *     LORIA, INRIA Lorraine,
40  *     Campus Scientifique, BP 239
41  *     54506 VANDOEUVRE LES NANCY CEDEX
42  *     FRANCE
43  *
44  */
45 
46 #include <geogram/basic/common.h>
47 #include <geogram/basic/logger.h>
48 #include <geogram/basic/command_line.h>
49 #include <geogram/basic/command_line_args.h>
50 #include <geogram/basic/progress.h>
51 #include <geogram/basic/stopwatch.h>
52 #include <geogram/basic/process.h>
53 #include <geogram/basic/file_system.h>
54 #include <geogram/mesh/mesh.h>
55 #include <geogram/mesh/mesh_io.h>
56 #include <geogram/mesh/mesh_distance.h>
57 #include <geogram/mesh/mesh_geometry.h>
58 #include <geogram/mesh/mesh_repair.h>
59 #include <geogram/mesh/mesh_topology.h>
60 
61 namespace {
62 
63     using namespace GEO;
64 
65     /**
66      * \return false if distance is greater than 5%
67      *  of bbox radius.
68      */
measure_distance(Mesh & M1,Mesh & M2)69     bool measure_distance(Mesh& M1, Mesh& M2) {
70         Logger::div("distance");
71         Stopwatch total("Hausdorff");
72 
73         double bbox_diag = bbox_diagonal(M2);
74         double sampling_step = CmdLine::get_arg_percent(
75             "stat:sampling_step", bbox_diag
76         );
77 
78         double sym_dist = 0.0, sym_dist_percent = 0.0;
79 
80         {
81             Stopwatch W("M1->M2");
82             Logger::out("Hausdorff") << "Computing Hausdorff distance M1->M2..."
83                 << std::endl;
84             double dist = mesh_one_sided_Hausdorff_distance(
85                 M1, M2, sampling_step
86             );
87             sym_dist = std::max(sym_dist, dist);
88             double dist_percent = dist / bbox_diag * 100.0;
89             Logger::out("Hausdorff") << "Hausdorff distance M1->M2: "
90                 << dist
91                 << " (" << dist_percent << "% bbox diag)"
92                 << std::endl;
93         }
94 
95         {
96             Stopwatch W("M2->M1");
97             Logger::out("Hausdorff") << "Computing Hausdorff distance M2->M1..."
98                 << std::endl;
99             double dist = mesh_one_sided_Hausdorff_distance(
100                 M2, M1, sampling_step
101             );
102             sym_dist = std::max(sym_dist, dist);
103             double dist_percent = dist / bbox_diag * 100.0;
104             Logger::out("Hausdorff") << "Hausdorff distance M2->M1: "
105                 << dist
106                 << " (" << dist_percent << "% bbox diag)"
107                 << std::endl;
108         }
109 
110         sym_dist_percent = sym_dist / bbox_diag * 100.0;
111         Logger::out("Hausdorff") << "Hausdorff distance M2<->M1: "
112             << sym_dist
113             << " (" << sym_dist_percent << "% bbox diag)"
114             << std::endl;
115 
116         return sym_dist_percent < 5.0;
117     }
118 }
119 
main(int argc,char ** argv)120 int main(int argc, char** argv) {
121     using namespace GEO;
122 
123     GEO::initialize();
124 
125     int result = 0;
126 
127     try {
128 
129         Stopwatch total("Total time");
130 
131         CmdLine::import_arg_group("standard");
132         CmdLine::import_arg_group("algo");
133         CmdLine::import_arg_group("stat");
134 
135         Logger::div("initialization");
136 
137         std::vector<std::string> filenames;
138         if(!CmdLine::parse(argc, argv, filenames, "mesh1 mesh2")) {
139             return 1;
140         }
141 
142         std::string mesh1_filename = filenames[0];
143         std::string mesh2_filename = filenames[1];
144 
145         Mesh M1;
146         if(!mesh_load(mesh1_filename, M1)) {
147             return 1;
148         }
149         mesh_repair(M1, MESH_REPAIR_TRIANGULATE);
150 
151         Mesh M2;
152         if(!mesh_load(mesh2_filename, M2)) {
153             return 1;
154         }
155         mesh_repair(M2, MESH_REPAIR_TRIANGULATE);
156 
157         if(!measure_distance(M1, M2)) {
158             Logger::warn("Distance") << "Deviation greater than threshold (5%)" << std::endl;
159             result = 2;
160         }
161 
162         if(!meshes_have_same_topology(M1, M2, true)) {
163             Logger::warn("Topology") << "Mesh topology differs" << std::endl;
164         }
165     }
166     catch(const std::exception& e) {
167         std::cerr << "Received an exception: " << e.what() << std::endl;
168         return 1;
169     }
170 
171     return result;
172 }
173 
174