Developer Documentation
subdivider.cc
1 /* ========================================================================= *
2  * *
3  * OpenMesh *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openmesh.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenMesh. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40  * ========================================================================= */
41 
42 /*===========================================================================*\
43  * *
44  * $Revision$ *
45  * $Date$ *
46  * *
47 \*===========================================================================*/
48 
49 #include <iostream>
50 #include <sstream>
51 // ---------------------------------------- OpenMesh Stuff
52 #include <OpenMesh/Core/IO/MeshIO.hh>
53 #include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
55 #include <OpenMesh/Tools/Utils/getopt.h>
56 // ---------------------------------------- Subdivider
64 
65 // ----------------------------------------------------------------------------
66 
67 using namespace OpenMesh::Subdivider;
68 
71 
80 
82 
83 // ----------------------------------------------------------------------------
84 
85 std::map< std::string, double > timings;
86 
87 // ----------------------------------------------------------------------------
88 
89 template < typename Subdivider >
90 bool subdivide( typename Subdivider::mesh_t& _m, size_t _n,
91  Timer::Format _fmt )
92 {
93  bool rc;
94  Timer t;
95  Subdivider subdivide;
96 
97  std::cout << "Subdivide " << _n
98  << " times with '" << subdivide.name() << "'\n";
99 
100  subdivide.attach(_m);
101  t.start();
102  rc=subdivide( _n );
103  t.stop();
104  subdivide.detach();
105 
106  if (rc)
107  {
108  std::cout << " Done [" << t.as_string(_fmt) << "]\n";
109  timings[subdivide.name()] = t.seconds();
110  }
111  else
112  std::cout << " Failed!\n";
113  return rc;
114 }
115 
116 // ----------------------------------------------------------------------------
117 
118 void usage_and_exit(int _xcode);
119 
120 // ----------------------------------------------------------------------------
121 
122 template < typename Subdivider >
123 int mainT( size_t _n,
124  const std::string& _ifname,
125  const std::string& _ofname,
126  const Timer::Format _fmt )
127 {
128  // -------------------- read mesh
129  std::cout << "Read mesh from file " << _ifname << std::endl;
130 
131  typename Subdivider::mesh_t mesh;
132 
133  if ( OpenMesh::IO::read_mesh( mesh, _ifname ) )
134  std::cout << " Ok\n";
135  else
136  {
137  std::cout << " Failed!\n";
138  return 1;
139  }
140 
141  std::cout << " #V " << mesh.n_vertices()
142  << ", #F " << mesh.n_faces()
143  << ", #E " << mesh.n_edges() << std::endl;
144 
145  // -------------------- subdividing
146  try
147  {
148  if (!subdivide< Subdivider >( mesh, _n, _fmt ))
149  return 1;
150  }
151  catch(std::bad_alloc& x)
152  {
153  std::cerr << "Out of memory: " << x.what() << std::endl;
154  return 1;
155  }
156  catch(std::exception& x)
157  {
158  std::cerr << x.what() << std::endl;
159  return 1;
160  }
161  catch(...)
162  {
163  std::cerr << "Unknown exception!\n";
164  return 1;
165  }
166 
167  // -------------------- write mesh
168 
169  std::cout << " #V " << mesh.n_vertices()
170  << ", #F " << mesh.n_faces()
171  << ", #E " << mesh.n_edges() << std::endl;
172 
173  if ( !_ofname.empty() )
174  {
175  std::cout << "Write resulting mesh to file " << _ofname << "..";
177  {
178  std::cout << "ok\n";
179  }
180  else
181  {
182  std::cerr << "Failed! Could not write file!\n";
183  return 1;
184  }
185  }
186 
187  return 0;
188 }
189 
190 // ----------------------------------------------------------------------------
191 
192 int main(int argc, char **argv)
193 {
194  int c;
195 
196  bool compare_all = false;
197  size_t n;
198  std::string ifname;
199  std::string ofname;
200 
201  enum {
202  TypeSqrt3,
203  TypeLoop,
204  TypeCompSqrt3,
205  TypeCompLoop,
206  TypeLabsikGreiner,
207  TypeModButterfly,
208  TypeCatmullClark
209  } st = TypeSqrt3;
210 
211  Timer::Format fmt = Timer::Automatic;
212 
213  while ( (c=getopt(argc, argv, "csSlLbBhf:"))!=-1 )
214  {
215  switch(c)
216  {
217  case 'c': compare_all=true; break;
218  case 's': st = TypeSqrt3; break;
219  case 'S': st = TypeCompSqrt3; break;
220  case 'l': st = TypeLoop; break;
221  case 'L': st = TypeCompLoop; break;
222  case 'b': st = TypeLabsikGreiner; break;
223  case 'B': st = TypeModButterfly; break;
224  case 'C': st = TypeCatmullClark; std::cerr << "Not yet supported, as it needs a poly mesh!"; break;
225  case 'f':
226  {
227  switch(*optarg)
228  {
229  case 'm': fmt = Timer::MSeconds; break;
230  case 'c': fmt = Timer::HSeconds; break;
231  case 's': fmt = Timer::Seconds; break;
232  case 'a':
233  default: fmt = Timer::Automatic; break;
234  }
235  break;
236  }
237  case 'h': usage_and_exit(0);
238  case '?':
239  default: usage_and_exit(1);
240  }
241  }
242 
243  if (argc-optind < 2)
244  usage_and_exit(1);
245 
246  // # iterations
247  {
248  std::stringstream str; str << argv[optind]; str >> n;
249  }
250 
251  // input file
252  ifname = argv[++optind];
253 
254  // output file, if provided
255  if ( ++optind < argc )
256  ofname = argv[optind];
257 
258 
259  // --------------------
260  if ( compare_all )
261  {
262  int rc;
263  rc = mainT<Sqrt3> ( n, ifname, "", fmt );
264  rc += mainT<Loop> ( n, ifname, "", fmt );
265  rc += mainT<CompositeSqrt3> ( n, ifname, "", fmt );
266  rc += mainT<CompositeLoop> ( n, ifname, "", fmt );
267  rc += mainT<InterpolatingSqrt3LG> ( n, ifname, "", fmt );
268  rc += mainT<ModifiedButterfly> ( n, ifname, "", fmt );
269  rc += mainT<CatmullClark> ( n, ifname, "", fmt );
270 
271  if (rc)
272  return rc;
273 
274  std::cout << std::endl;
275 
276  std::map< std::string, double >::iterator it;
277 
278  std::cout << "Timings:\n";
279  for(it = timings.begin();it!=timings.end();++it)
280  std::cout << it->first << ": " << Timer::as_string(it->second)
281  << std::endl;
282  std::cout << std::endl;
283  std::cout << "Ratio composite/native algorithm:\n";
284  std::cout << "sqrt(3): "
285  << timings["Uniform Composite Sqrt3"]/timings["Uniform Sqrt3"]
286  << std::endl
287  << "loop : "
288  << timings["Uniform Composite Loop"]/timings["Uniform Loop"]
289  << std::endl
290  << "Interpolating sqrt(3) : "
291  << timings["Uniform Interpolating Sqrt3"]/timings["Uniform Sqrt3"]
292  << std::endl;
293  return 0;
294  }
295  else switch(st)
296  {
297  case TypeSqrt3:
298  return mainT<Sqrt3>( n, ifname, ofname, fmt );
299  case TypeLoop:
300  return mainT<Loop>( n, ifname, ofname, fmt );
301  case TypeCompSqrt3:
302  return mainT<CompositeSqrt3>( n, ifname, ofname, fmt );
303  case TypeCompLoop:
304  return mainT<CompositeLoop> ( n, ifname, ofname, fmt );
305  case TypeLabsikGreiner:
306  return mainT<InterpolatingSqrt3LG> ( n, ifname, ofname, fmt );
307  case TypeModButterfly:
308  return mainT<ModifiedButterfly> ( n, ifname, ofname, fmt );
309  case TypeCatmullClark:
310  return mainT<CatmullClark> ( n, ifname, ofname, fmt );
311  }
312  return 1;
313 }
314 
315 // ----------------------------------------------------------------------------
316 
317 void usage_and_exit(int _xcode)
318 {
319  std::cout << "Usage: subdivide [Subdivider Type] #Iterations Input [Output].\n";
320  std::cout << std::endl;
321  std::cout << "Subdivider Type\n"
322  << std::endl
323  << " -l\tLoop\n"
324  << " -L\tComposite Loop\n"
325  << " -s\tSqrt3\n"
326  << " -S\tComposite Sqrt3\n"
327  << " -b\tInterpolating Sqrt3 Labsik-Greiner\n"
328  << " -B\tModified Butterfly\n"
329  // << " -C\tCatmullClark\n"
330  << std::endl;
331  exit(_xcode);
332 }
Set binary mode for r/w.
Definition: Options.hh:105
void start(void)
Start measurement.
double seconds(void) const
Returns measured time in seconds, if the timer is in state &#39;Stopped&#39;.
bool read_mesh(Mesh &_mesh, const std::string &_filename)
Read a mesh from file _filename.
Definition: MeshIO.hh:104
std::string as_string(Format format=Automatic)
void stop(void)
Stop measurement.
bool write_mesh(const Mesh &_mesh, const std::string &_filename, Options _opt=Options::Default, std::streamsize _precision=6)
Write a mesh to the file _filename.
Definition: MeshIO.hh:199