Developer Documentation
SubdivideWidget.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 //=============================================================================
50 //
51 // CLASS SubdivideWidget - IMPLEMENTATION
52 //
53 //=============================================================================
54 
55 #ifndef SUBDIVIDEWIDGET_CC
56 #define SUBDIVIDEWIDGET_CC
57 
58 //== INCLUDES =================================================================
59 
60 
61 // Qt
62 #include <QApplication>
63 #include <QFileDialog>
64 #include <QButtonGroup>
65 #include <QRadioButton>
66 #include <QVBoxLayout>
67 #include <QHBoxLayout>
68 #include <QPushButton>
69 #include <QLabel>
70 #include <QString>
71 #include <QMessageBox>
72 
73 // OpenMesh
74 #include <OpenMesh/Core/IO/MeshIO.hh>
75 #include <OpenMesh/Core/Mesh/PolyConnectivity.hh>
83 
84 #include <OpenMesh/Apps/Subdivider/SubdivideWidget.hh>
85 
86 
87 using namespace OpenMesh::Subdivider;
88 
89 //== IMPLEMENTATION ==========================================================
90 
91 
93 SubdivideWidget(QWidget* _parent, const char* _name)
94  : QWidget(_parent),
95  timer_(NULL), animate_step_(0), max_animate_steps_(4), msecs_(0)
96 {
97 
98  setWindowTitle( QString(_name) );
99 
100  QVBoxLayout* vbox = new QVBoxLayout();
101 
102  cur_topo_type = SOP_Undefined;
103  // sel_topo_type will be set when adding the radio button.;
104 
105  // examiner widget
106  viewer_widget_ = new MeshViewerWidget();
107 
108  vbox->addWidget(viewer_widget_);
109 
110  QHBoxLayout* hbox = new QHBoxLayout();
111 // hbox->setFixedSize(400, 30);
112  vbox->addLayout(hbox);
113 
114  // insert subdivision pushbutton
115  QPushButton* subdiv_button = new QPushButton( "Subdivide");
116  subdiv_button->setMinimumWidth(50);
117  QObject::connect( subdiv_button, SIGNAL( clicked() ),
118  this, SLOT( subdiv_slot() ) );
119  hbox->addWidget(subdiv_button);
120 
121  // insert load pushbutton
122  QPushButton* load_button = new QPushButton( "Load Mesh");
123  load_button->setMinimumWidth(50);
124  QObject::connect( load_button, SIGNAL( clicked() ),
125  this, SLOT( load_slot() ) );
126  hbox->addWidget(load_button);
127 
128  // insert save pushbutton
129  QPushButton* save_button = new QPushButton( "Save Mesh");
130  save_button->setMinimumWidth(50);
131  QObject::connect( save_button, SIGNAL( clicked() ),
132  this, SLOT( save_slot() ) );
133  hbox->addWidget(save_button);
134 
135 
136  // insert reset pushbutton
137  QPushButton* reset_button = new QPushButton( "Reset");
138  reset_button->setMinimumWidth(50);
139  QObject::connect( reset_button, SIGNAL( clicked() ),
140  this, SLOT( reset_slot() ) );
141  hbox->addWidget(reset_button);
142 
143 
144  // Create an exclusive button group: Topology Operators
145 // QButtonGroup *bgrp1 = new QButtonGroup( 1, QGroupBox::Vertical,"Subdivision Operators:");
146 
147  QButtonGroup* buttonGroup = new QButtonGroup();
148 
149  buttonGroup->setExclusive( true );
150 
151  // insert 2 radiobuttons
152  QRadioButton* radio1 = new QRadioButton( "Comp. Loop" );
153  QRadioButton* radio2 = new QRadioButton( "Comp. SQRT(3)" );
154  QRadioButton* radio3 = new QRadioButton( "Loop" );
155  QRadioButton* radio4 = new QRadioButton( "Sqrt(3)" );
156  QRadioButton* radio5 = new QRadioButton( "Interpolating Sqrt3" );
157  QRadioButton* radio6 = new QRadioButton( "Modified Butterfly" );
158  // QRadioButton* radio7 = new QRadioButton( "Catmull Clark" ); // Disabled, as it needs a quad mesh!
159  radio3->setChecked( true );
160  sel_topo_type = SOP_UniformLoop;
161 
162  buttonGroup->addButton(radio1, SOP_UniformCompositeLoop);
163  buttonGroup->addButton(radio2, SOP_UniformCompositeSqrt3);
164  buttonGroup->addButton(radio3, SOP_UniformLoop);
165  buttonGroup->addButton(radio4, SOP_UniformSqrt3);
166  buttonGroup->addButton(radio5, SOP_UniformInterpolatingSqrt3);
167  buttonGroup->addButton(radio6, SOP_ModifiedButterfly);
168  //buttonGroup->addButton(radio7, SOP_CatmullClark);
169 
170  vbox->addWidget(radio1);
171  vbox->addWidget(radio2);
172  vbox->addWidget(radio3);
173  vbox->addWidget(radio4);
174  vbox->addWidget(radio5);
175  vbox->addWidget(radio6);
176  // vbox->addWidget(radio7);
177 
178  QObject::connect( buttonGroup, SIGNAL( buttonPressed(int) ),
179  this, SLOT( slot_select_sop(int) ) );
180 
181 
182  status_bar = new QStatusBar();
183  status_bar->setFixedHeight(20);
184  status_bar->showMessage("0 Faces, 0 Edges, 0 Vertices");
185  vbox->addWidget(status_bar);
186 
187 
188  setLayout(vbox);
189 
190 
191  // animation
192  timer_ = new QTimer(this);
193  connect( timer_, SIGNAL( timeout() ), this, SLOT( animate_slot() ) );
194 
195  // --------------------
196 
197  subdivider_[SOP_UniformCompositeLoop] = new Uniform::CompositeLoopT<Mesh>;
198  subdivider_[SOP_UniformCompositeSqrt3] = new Uniform::CompositeSqrt3T<Mesh>;
199  subdivider_[SOP_UniformLoop] = new Uniform::LoopT<Mesh>;
200  subdivider_[SOP_UniformSqrt3] = new Uniform::Sqrt3T<Mesh>;
201  subdivider_[SOP_UniformInterpolatingSqrt3] = new Uniform::InterpolatingSqrt3LGT< Mesh >;
202  subdivider_[SOP_ModifiedButterfly] = new Uniform::ModifiedButterflyT<Mesh>;
203  subdivider_[SOP_CatmullClark] = new Uniform::CatmullClarkT<Mesh>;
204 
205 }
206 
207 
208 //-----------------------------------------------------------------------------
209 
210 void SubdivideWidget::slot_select_sop(int i)
211 {
212  switch(i)
213  {
214  case SOP_UniformCompositeLoop:
215  case SOP_UniformCompositeSqrt3:
216  case SOP_UniformLoop:
217  case SOP_UniformSqrt3:
218  case SOP_UniformInterpolatingSqrt3:
219  case SOP_ModifiedButterfly:
220  case SOP_CatmullClark: sel_topo_type = (SOPType)i; break;
221  default: sel_topo_type = SOP_Undefined;
222  }
223 }
224 
225 
226 //-----------------------------------------------------------------------------
227 
228 void SubdivideWidget::keyPressEvent( QKeyEvent *k )
229 {
230  bool timerStopped = false;
231  if ( timer_->isActive())
232  {
233  timer_->stop();
234  timerStopped = true;
235  }
236 
237  switch ( k->key() )
238  {
239  case Qt::Key_R: // reset
240  reset_slot();
241  break;
242  case Qt::Key_S: // save
243  save_slot();
244  break;
245  case Qt::Key_L: // load
246  load_slot();
247  break;
248 
249  case Qt::Key_A:
250 
251  if ( timerStopped )
252  break;
253 
254  if (timer_->isActive())
255  {
256  timer_->stop();
257  }
258  else
259  {
260  reset_slot();
261  timer_->setSingleShot( true );
262  timer_->start(0);
263  }
264  break;
265 
266  case ' ': // subdivide
267  subdiv_slot();
268  }
269 }
270 
271 
272 
273 //-----------------------------------------------------------------------------
274 
275 
276 void SubdivideWidget::update()
277 {
278  size_t n_faces = viewer_widget_->mesh().n_faces();
279  size_t n_edges = viewer_widget_->mesh().n_edges();
280  size_t n_vertices = viewer_widget_->mesh().n_vertices();
281  QString message(""), temp;
282  message.append(temp.setNum(n_faces));
283  message.append(" Faces, ");
284  message.append(temp.setNum(n_edges));
285  message.append(" Edges, ");
286  message.append(temp.setNum(n_vertices));
287  message.append(" Vertices. ");
288  if (msecs_)
289  {
290  message.append(temp.setNum(msecs_/1000.0));
291  message.append("s");
292  }
293  status_bar->showMessage(message);
294 }
295 
296 
297 //-----------------------------------------------------------------------------
298 
299 
300 void SubdivideWidget::reset_slot()
301 {
302  if (cur_topo_type != SOP_Undefined)
303  subdivider_[cur_topo_type]->detach();
304 
305  viewer_widget_->mesh() = viewer_widget_->orig_mesh();
306  viewer_widget_->mesh().update_face_normals();
307  viewer_widget_->mesh().update_vertex_normals();
308  viewer_widget_->updateGL();
309  update();
310  cur_topo_type = SOP_Undefined;
311 }
312 
313 
314 
315 //-----------------------------------------------------------------------------
316 
317 
318 void SubdivideWidget::subdiv_slot()
319 {
320  assert( sel_topo_type != SOP_Undefined );
321 
322  //QTime t;
323  using namespace OpenMesh::Subdivider::Uniform;
324 
325  status_bar->showMessage( "processing subdivision step...");
326 
327  if (cur_topo_type != sel_topo_type)
328  {
329  if (cur_topo_type!=SOP_Undefined)
330  subdivider_[cur_topo_type]->detach();
331  subdivider_[cur_topo_type=sel_topo_type]->attach(viewer_widget_->mesh());
332  }
333 
334  std::clog << "subdiving...\n";
335  (*subdivider_[sel_topo_type])(1);
336  std::clog << "subdiving...done\n";
337 
338  // Update viewer
339  viewer_widget_->mesh().update_normals();
340  viewer_widget_->updateGL();
341 
342  // Update status bar information
343  update();
344 }
345 
346 
347 //-----------------------------------------------------------------------------
348 
349 bool
350 SubdivideWidget::open_mesh(const char* _filename)
351 {
353 
354  if (viewer_widget_->open_mesh(_filename, opt))
355  {
356  update();
357  return true;
358  }
359 
360  return false;
361 }
362 
363 
364 //-----------------------------------------------------------------------------
365 
366 void
367 SubdivideWidget::save_slot()
368 {
370 
371  QString write_filter(IOManager().qt_write_filters().c_str());
372  QString filename = QFileDialog::getSaveFileName(this, "", "", write_filter);
373 
374  if (!filename.isEmpty()){
375  if (OpenMesh::IO::write_mesh(viewer_widget_->mesh(), filename.toStdString(),
377  std::cerr << "ok\n";
378  else
379  std::cerr << "FAILED\n";
380  }
381 }
382 
383 
384 //-----------------------------------------------------------------------------
385 
386 void
387 SubdivideWidget::load_slot()
388 {
390 
391  QString read_filter(IOManager().qt_read_filters().c_str());
392  QString filename =
393  QFileDialog::getOpenFileName(this, "", "", read_filter);
394 
395  if (!filename.isNull())
396  {
397 
398  if (cur_topo_type != SOP_Undefined)
399  subdivider_[cur_topo_type]->detach();
400 
402  std::string file( filename.toStdString() );
403 
404  if ( !viewer_widget_->open_mesh(file.c_str() , opt) )
405  {
406  QString msg = "Cannot read mesh from file ";
407  QMessageBox::critical( this,"", msg + filename, QMessageBox::Ok );
408  }
409 
410  update();
411  cur_topo_type = SOP_Undefined;
412  }
413 }
414 
415 
416 //-----------------------------------------------------------------------------
417 
418 void
419 SubdivideWidget::animate_slot()
420 {
421  if (++animate_step_ < max_animate_steps_)
422  {
423  subdiv_slot();
424  }
425  else
426  {
427  reset_slot();
428  animate_step_ = 0;
429  }
430  timer_->setSingleShot(true);
431  timer_->start( 500 );
432 }
433 
434 //=============================================================================
435 #endif //SUBDIVIDEWIDGET_CC deifined
436 //=============================================================================
Set binary mode for r/w.
Definition: Options.hh:105
SubdivideWidget(QWidget *_parent=0, const char *_name=0)
constructor
Set options for reader/writer modules.
Definition: Options.hh:95
bool open_mesh(const char *_filename)
open mesh from _filename
_IOManager_ & IOManager()
Definition: IOManager.cc:77
QStatusBar * status_bar
Updates Status Bar Information.
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