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