Developer Documentation
VDPMSynthesizerViewerWidget.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 newClass - IMPLEMENTATION
47 //
48 //=============================================================================
49 
50 //== INCLUDES =================================================================
51 
52 #ifdef _MSC_VER
53 # pragma warning(disable: 4267 4311)
54 #endif
55 
56 #include <iostream>
57 #include <fstream>
58 #include <map>
59 
60 #include <QApplication>
61 #include <QDateTime>
62 #include <QFileDialog>
63 #include <QDataStream>
64 
65 #include <OpenMesh/Core/IO/MeshIO.hh>
66 #include <OpenMesh/Core/IO/BinaryHelper.hh>
67 #include <OpenMesh/Core/Utils/Endian.hh>
69 #include <OpenMesh/Apps/VDProgMesh/Synthesizer/VDPMSynthesizerViewerWidget.hh>
70 
71 
72 //== NAMESPACES ===============================================================
73 
74 
75 namespace OpenMesh {
76 
77 
78 //== IMPLEMENTATION ==========================================================
79 
80 VDPMSynthesizerViewerWidget::VDPMSynthesizerViewerWidget(QWidget* _parent, const char* _name)
81  : MeshViewerWidget(_parent),
82  kappa_square_(0.0),
83  adaptive_mode_(false),
84  n_base_vertices_(0),
85  n_base_edges_(0),
86  n_base_faces_(0),
87  n_details_(0)
88 
89 {
90  adaptive_mode_ = true;
91 }
92 
93 VDPMSynthesizerViewerWidget::~VDPMSynthesizerViewerWidget()
94 {
95 
96 }
97 
98 void
99 VDPMSynthesizerViewerWidget::
100 draw_scene(const std::string &_draw_mode)
101 {
102  if (adaptive_mode_ == true)
103  {
104  adaptive_refinement();
105  }
106  MeshViewerWidget::draw_scene(_draw_mode);
107 }
108 
109 
110 void
111 VDPMSynthesizerViewerWidget::
112 adaptive_refinement()
113 {
114  update_viewing_parameters();
115 
116  VDPMMesh::HalfedgeHandle v0v1;
117 
118  float fovy = viewing_parameters_.fovy();
119 
120  float tolerance_square = viewing_parameters_.tolerance_square();
121  float tan_value = tanf(fovy / 2.0f);
122 
123  kappa_square_ = 4.0f * tan_value * tan_value * tolerance_square;
124 
125  //assert( !vfront_.end() );
126 
127  for ( vfront_.begin(); !vfront_.end(); )
128  {
130  node_handle = vfront_.node_handle(),
131  parent_handle = vhierarchy_.parent_handle(node_handle);
132 
133  if (vhierarchy_.is_leaf_node(node_handle) != true &&
134  qrefine(node_handle) == true)
135  {
136  force_vsplit(node_handle);
137  }
138  else if (vhierarchy_.is_root_node(node_handle) != true &&
139  ecol_legal(parent_handle, v0v1) == true &&
140  qrefine(parent_handle) != true)
141  {
142  ecol(parent_handle, v0v1);
143  }
144  else
145  {
146  vfront_.next();
147  }
148  }
149 
150  // free memories tagged as 'deleted'
151  mesh_.garbage_collection(false, true, true);
152  mesh_.update_face_normals();
153 }
154 
155 
156 bool
157 VDPMSynthesizerViewerWidget::
158 qrefine(VHierarchyNodeHandle _node_handle)
159 {
160  VHierarchyNode &node = vhierarchy_.node(_node_handle);
161  Vec3f p = mesh_.point(node.vertex_handle());
162  Vec3f eye_dir = p - viewing_parameters_.eye_pos();;
163 
164  float distance = eye_dir.length();
165  float distance2 = distance * distance;
166  float product_value = dot(eye_dir, node.normal());
167 
168  if (outside_view_frustum(p, node.radius()) == true)
169  return false;
170 
171  if (oriented_away(node.sin_square(), distance2, product_value) == true)
172  return false;
173 
174  if (screen_space_error(node.mue_square(),
175  node.sigma_square(),
176  distance2,
177  product_value) == true)
178  return false;
179 
180  return true;
181 }
182 
183 
184 void
185 VDPMSynthesizerViewerWidget::
186 force_vsplit(VHierarchyNodeHandle node_handle)
187 {
188  VDPMMesh::VertexHandle vl, vr;
189 
190  get_active_cuts(node_handle, vl, vr);
191 
192  while (vl == vr)
193  {
194  force_vsplit(mesh_.data(vl).vhierarchy_node_handle());
195  get_active_cuts(node_handle, vl, vr);
196  }
197 
198  vsplit(node_handle, vl, vr);
199 }
200 
201 
202 
203 void
204 VDPMSynthesizerViewerWidget::
205 vsplit(VHierarchyNodeHandle _node_handle,
208 {
209  // refine
211  lchild_handle = vhierarchy_.lchild_handle(_node_handle),
212  rchild_handle = vhierarchy_.rchild_handle(_node_handle);
213 
214  VDPMMesh::VertexHandle v0 = vhierarchy_.vertex_handle(lchild_handle);
215  VDPMMesh::VertexHandle v1 = vhierarchy_.vertex_handle(rchild_handle);
216 
217  mesh_.vertex_split(v0, v1, vl, vr);
218  mesh_.set_normal(v0, vhierarchy_.normal(lchild_handle));
219  mesh_.set_normal(v1, vhierarchy_.normal(rchild_handle));
220  mesh_.data(v0).set_vhierarchy_node_handle(lchild_handle);
221  mesh_.data(v1).set_vhierarchy_node_handle(rchild_handle);
222  mesh_.status(v0).set_deleted(false);
223  mesh_.status(v1).set_deleted(false);
224 
225  vfront_.remove(_node_handle);
226  vfront_.add(lchild_handle);
227  vfront_.add(rchild_handle);
228 }
229 
230 
231 void
232 VDPMSynthesizerViewerWidget::
233 ecol(VHierarchyNodeHandle _node_handle, const VDPMMesh::HalfedgeHandle& v0v1)
234 {
236  lchild_handle = vhierarchy_.lchild_handle(_node_handle),
237  rchild_handle = vhierarchy_.rchild_handle(_node_handle);
238 
239  VDPMMesh::VertexHandle v0 = vhierarchy_.vertex_handle(lchild_handle);
240  VDPMMesh::VertexHandle v1 = vhierarchy_.vertex_handle(rchild_handle);
241 
242  // coarsen
243  mesh_.collapse(v0v1);
244  mesh_.set_normal(v1, vhierarchy_.normal(_node_handle));
245  mesh_.data(v0).set_vhierarchy_node_handle(lchild_handle);
246  mesh_.data(v1).set_vhierarchy_node_handle(_node_handle);
247  mesh_.status(v0).set_deleted(false);
248  mesh_.status(v1).set_deleted(false);
249 
250  vfront_.add(_node_handle);
251  vfront_.remove(lchild_handle);
252  vfront_.remove(rchild_handle);
253 }
254 
255 
256 bool
257 VDPMSynthesizerViewerWidget::
258 ecol_legal(VHierarchyNodeHandle _parent_handle, VDPMMesh::HalfedgeHandle& v0v1)
259 {
261  lchild_handle = vhierarchy_.lchild_handle(_parent_handle),
262  rchild_handle = vhierarchy_.rchild_handle(_parent_handle);
263 
264  // test whether lchild & rchild present in the current vfront
265  if ( vfront_.is_active(lchild_handle) != true ||
266  vfront_.is_active(rchild_handle) != true)
267  return false;
268 
269  VDPMMesh::VertexHandle v0, v1;
270 
271  v0 = vhierarchy_.vertex_handle(lchild_handle);
272  v1 = vhierarchy_.vertex_handle(rchild_handle);
273 
274  v0v1 = mesh_.find_halfedge(v0, v1);
275 
276  return mesh_.is_collapse_ok(v0v1);
277 }
278 
279 void
280 VDPMSynthesizerViewerWidget::
281 get_active_cuts(const VHierarchyNodeHandle _node_handle,
283 {
285  VHierarchyNodeHandle nnode_handle;
286 
288  nnode_index,
289  fund_lcut_index = vhierarchy_.fund_lcut_index(_node_handle),
290  fund_rcut_index = vhierarchy_.fund_rcut_index(_node_handle);
291 
292  vl = VDPMMesh::InvalidVertexHandle;
293  vr = VDPMMesh::InvalidVertexHandle;
294 
295  for (vv_it=mesh_.vv_iter(vhierarchy_.vertex_handle(_node_handle));
296  vv_it.is_valid(); ++vv_it)
297  {
298  nnode_handle = mesh_.data(*vv_it).vhierarchy_node_handle();
299  nnode_index = vhierarchy_.node_index(nnode_handle);
300 
301  if (vl == VDPMMesh::InvalidVertexHandle &&
302  vhierarchy_.is_ancestor(nnode_index, fund_lcut_index) == true)
303  vl = *vv_it;
304 
305  if (vr == VDPMMesh::InvalidVertexHandle &&
306  vhierarchy_.is_ancestor(nnode_index, fund_rcut_index) == true)
307  vr = *vv_it;
308 
309  /*if (vl == VDPMMesh::InvalidVertexHandle && nnode_index.is_ancestor_index(fund_lcut_index) == true)
310  vl = *vv_it;
311  if (vr == VDPMMesh::InvalidVertexHandle && nnode_index.is_ancestor_index(fund_rcut_index) == true)
312  vr = *vv_it;*/
313 
314  if (vl != VDPMMesh::InvalidVertexHandle &&
315  vr != VDPMMesh::InvalidVertexHandle)
316  break;
317  }
318 }
319 
320 
321 bool
322 VDPMSynthesizerViewerWidget::
323 outside_view_frustum(const Vec3f &pos, float radius)
324 {
325 #if 0
326  return
327  (frustum_plane_[0].signed_distance(pos) < -radius) ||
328  (frustum_plane_[1].signed_distance(pos) < -radius) ||
329  (frustum_plane_[2].signed_distance(pos) < -radius) ||
330  (frustum_plane_[3].signed_distance(pos) < -radius);
331 #else
332 
333  Plane3d frustum_plane[4];
334 
335  viewing_parameters_.frustum_planes(frustum_plane);
336 
337  for (int i = 0; i < 4; i++) {
338  if (frustum_plane[i].singed_distance(pos) < -radius)
339  return true;
340  }
341  return false;
342 #endif
343 }
344 
345 bool
346 VDPMSynthesizerViewerWidget::
347 oriented_away(float sin_square, float distance_square, float product_value)
348 {
349 #if 0
350  return (product_value > 0)
351  && ((product_value * product_value) > (distance_square * sin_square));
352 #else
353  if (product_value > 0 &&
354  product_value * product_value > distance_square * sin_square)
355  return true;
356  else
357  return false;
358 #endif
359 }
360 
361 
362 bool
363 VDPMSynthesizerViewerWidget::
364 screen_space_error(float mue_square, float sigma_square,
365  float distance_square, float product_value)
366 {
367 #if 0
368  float ks_ds = kappa_square_ * distance_square;
369  float pv_pv = product_value * product_value;
370  return (mue_square >= ks_ds)
371  || (sigma_square*( distance_square - pv_pv) >= ks_ds*distance_square);
372 #else
373  if ((mue_square >= kappa_square_ * distance_square) ||
374  (sigma_square * (distance_square - product_value * product_value) >= kappa_square_ * distance_square * distance_square))
375  return false;
376  else
377  return true;
378 #endif
379 }
380 
381 void
382 VDPMSynthesizerViewerWidget::
383 open_vd_prog_mesh(const char* _filename)
384 {
385  unsigned int i;
386  unsigned int value;
387  unsigned int fvi[3];
388  char fileformat[16];
389  Vec3f p, normal;
390  float radius, sin_square, mue_square, sigma_square;
391  VHierarchyNodeHandleContainer roots;
392  VertexHandle vertex_handle;
393  VHierarchyNodeIndex node_index;
394  VHierarchyNodeIndex lchild_node_index, rchild_node_index;
395  VHierarchyNodeIndex fund_lcut_index, fund_rcut_index;
396  VHierarchyNodeHandle node_handle;
397  VHierarchyNodeHandle lchild_node_handle, rchild_node_handle;
398 
399  std::map<VHierarchyNodeIndex, VHierarchyNodeHandle> index2handle_map;
400 
401  std::ifstream ifs(_filename, std::ios::binary);
402 
403  if (!ifs)
404  {
405  std::cerr << "read error\n";
406  exit(1);
407  }
408 
409  //
410  bool swap = Endian::local() != Endian::LSB;
411 
412  // read header
413  ifs.read(fileformat, 10); fileformat[10] = '\0';
414  if (std::string(fileformat) != std::string("VDProgMesh"))
415  {
416  std::cerr << "Wrong file format.\n";
417  ifs.close();
418  exit(1);
419  }
420 
421  IO::restore(ifs, n_base_vertices_, swap);
422  IO::restore(ifs, n_base_faces_, swap);
423  IO::restore(ifs, n_details_, swap);
424 
425  mesh_.clear();
426  vfront_.clear();
427  vhierarchy_.clear();
428 
429  vhierarchy_.set_num_roots(n_base_vertices_);
430 
431  // load base mesh
432  for (i=0; i<n_base_vertices_; ++i)
433  {
434  IO::restore(ifs, p, swap);
435  IO::restore(ifs, radius, swap);
436  IO::restore(ifs, normal, swap);
437  IO::restore(ifs, sin_square, swap);
438  IO::restore(ifs, mue_square, swap);
439  IO::restore(ifs, sigma_square, swap);
440 
441  vertex_handle = mesh_.add_vertex(p);
442  node_index = vhierarchy_.generate_node_index(i, 1);
443  node_handle = vhierarchy_.add_node();
444 
445  VHierarchyNode &node = vhierarchy_.node(node_handle);
446 
447  node.set_index(node_index);
448  node.set_vertex_handle(vertex_handle);
449  mesh_.data(vertex_handle).set_vhierarchy_node_handle(node_handle);
450 
451  node.set_radius(radius);
452  node.set_normal(normal);
453  node.set_sin_square(sin_square);
454  node.set_mue_square(mue_square);
455  node.set_sigma_square(sigma_square);
456  mesh_.set_normal(vertex_handle, normal);
457 
458  index2handle_map[node_index] = node_handle;
459  roots.push_back(node_handle);
460  }
461  vfront_.init(roots, n_details_);
462 
463  for (i=0; i<n_base_faces_; ++i)
464  {
465  IO::restore(ifs, fvi[0], swap);
466  IO::restore(ifs, fvi[1], swap);
467  IO::restore(ifs, fvi[2], swap);
468 
469  mesh_.add_face(mesh_.vertex_handle(fvi[0]),
470  mesh_.vertex_handle(fvi[1]),
471  mesh_.vertex_handle(fvi[2]));
472  }
473 
474  // load details
475  for (i=0; i<n_details_; ++i)
476  {
477  // position of v0
478  IO::restore(ifs, p, swap);
479 
480  // vsplit info.
481  IO::restore(ifs, value, swap);
482  node_index = VHierarchyNodeIndex(value);
483 
484  IO::restore(ifs, value, swap);
485  fund_lcut_index = VHierarchyNodeIndex(value);
486 
487  IO::restore(ifs, value, swap);
488  fund_rcut_index = VHierarchyNodeIndex(value);
489 
490 
491  node_handle = index2handle_map[node_index];
492  vhierarchy_.make_children(node_handle);
493 
494  VHierarchyNode &node = vhierarchy_.node(node_handle);
495  VHierarchyNode &lchild = vhierarchy_.node(node.lchild_handle());
496  VHierarchyNode &rchild = vhierarchy_.node(node.rchild_handle());
497 
498  node.set_fund_lcut(fund_lcut_index);
499  node.set_fund_rcut(fund_rcut_index);
500 
501  vertex_handle = mesh_.add_vertex(p);
502  lchild.set_vertex_handle(vertex_handle);
503  rchild.set_vertex_handle(node.vertex_handle());
504 
505  index2handle_map[lchild.node_index()] = node.lchild_handle();
506  index2handle_map[rchild.node_index()] = node.rchild_handle();
507 
508  // view-dependent parameters
509  IO::restore(ifs, radius, swap);
510  IO::restore(ifs, normal, swap);
511  IO::restore(ifs, sin_square, swap);
512  IO::restore(ifs, mue_square, swap);
513  IO::restore(ifs, sigma_square, swap);
514  lchild.set_radius(radius);
515  lchild.set_normal(normal);
516  lchild.set_sin_square(sin_square);
517  lchild.set_mue_square(mue_square);
518  lchild.set_sigma_square(sigma_square);
519 
520  IO::restore(ifs, radius, swap);
521  IO::restore(ifs, normal, swap);
522  IO::restore(ifs, sin_square, swap);
523  IO::restore(ifs, mue_square, swap);
524  IO::restore(ifs, sigma_square, swap);
525  rchild.set_radius(radius);
526  rchild.set_normal(normal);
527  rchild.set_sin_square(sin_square);
528  rchild.set_mue_square(mue_square);
529  rchild.set_sigma_square(sigma_square);
530  }
531 
532  ifs.close();
533 
534  // update face and vertex normals
535  mesh_.update_face_normals();
536 
537  // bounding box
538  VDPMMesh::ConstVertexIter
539  vIt(mesh_.vertices_begin()),
540  vEnd(mesh_.vertices_end());
541 
542  VDPMMesh::Point bbMin, bbMax;
543 
544  bbMin = bbMax = mesh_.point(*vIt);
545  for (; vIt!=vEnd; ++vIt)
546  {
547  bbMin.minimize(mesh_.point(*vIt));
548  bbMax.maximize(mesh_.point(*vIt));
549  }
550 
551  // set center and radius
552  set_scene_pos(0.5f*(bbMin + bbMax), 0.5*(bbMin - bbMax).norm());
553 
554  // info
555  std::cerr << mesh_.n_vertices() << " vertices, "
556  << mesh_.n_edges() << " edge, "
557  << mesh_.n_faces() << " faces, "
558  << n_details_ << " detail vertices\n";
559 
560  updateGL();
561 }
562 
563 
564 void VDPMSynthesizerViewerWidget::keyPressEvent(QKeyEvent* _event)
565 {
566  switch (_event->key())
567  {
568  case Key_Home:
569  updateGL();
570  break;
571 
572  case Key_End:
573  updateGL();
574  break;
575 
576  case Key_Minus:
577  viewing_parameters_.increase_tolerance();
578  std::cout << "Scree-space error tolerance^2 is increased by "
579  << viewing_parameters_.tolerance_square() << std::endl;
580  updateGL();
581  break;
582 
583  case Key_Plus:
584  viewing_parameters_.decrease_tolerance();
585  std::cout << "Screen-space error tolerance^2 is decreased by "
586  << viewing_parameters_.tolerance_square() << std::endl;
587  updateGL();
588  break;
589 
590  case Key_A:
591  adaptive_mode_ = !(adaptive_mode_);
592  std::cout << "Adaptive refinement mode is "
593  << (adaptive_mode_ ? "on" : "off") << std::endl;
594  updateGL();
595  break;
596 
597  case Key_O:
598  qFilename_ = QFileDialog::getOpenFileName(0,"", "", "*.spm");
599  open_vd_prog_mesh( qFilename_.toStdString().c_str() );
600  break;
601 
602  default:
603  MeshViewerWidget::keyPressEvent( _event );
604  }
605 
606 }
607 
608 
609 
610 
611 
612 void
613 VDPMSynthesizerViewerWidget::
614 update_viewing_parameters()
615 {
616  viewing_parameters_.set_modelview_matrix(modelview_matrix());
617  viewing_parameters_.set_aspect((float) width()/ (float) height());
618  viewing_parameters_.set_fovy(fovy());
619 
620  viewing_parameters_.update_viewing_configurations();
621 }
622 
623 
624 //=============================================================================
625 } // namespace OpenMesh
626 //=============================================================================
Kernel::VertexVertexIter VertexVertexIter
Circulator.
Definition: PolyMeshT.hh:162
VHierarchyNodeHandle rchild_handle()
Returns handle to right child.
Kernel::Point Point
Coordinate type.
Definition: PolyMeshT.hh:112
virtual void draw_scene(const std::string &_draw_mode) override
inherited drawing method
Handle for a vertex entity.
Definition: Handles.hh:120
HalfedgeHandle vertex_split(Point _v0_point, VertexHandle _v1, VertexHandle _vl, VertexHandle _vr)
Vertex Split: inverse operation to collapse().
Definition: TriMeshT.hh:214
VHierarchyNodeHandle lchild_handle()
Returns handle to left child.
SmartVertexHandle add_vertex(const Point &_p)
Alias for new_vertex(const Point&).
Definition: PolyMeshT.hh:235
void update_face_normals()
Update normal vectors for all faces.
auto length() const -> decltype(std::declval< VectorT< S, DIM >>().norm())
compute squared euclidean norm
Definition: Vector11T.hh:423
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Definition: PolyMeshT.hh:136