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