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