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