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>
68 #include <OpenMesh/Tools/Utils/Timer.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 {
122 VHierarchyNodeHandle
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,
199 VDPMMesh::VertexHandle vl,
200 VDPMMesh::VertexHandle vr)
201 {
202 // refine
203 VHierarchyNodeHandle
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 {
228 VHierarchyNodeHandle
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 {
253 VHierarchyNodeHandle
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,
275 VDPMMesh::VertexHandle &vl, VDPMMesh::VertexHandle &vr)
276 {
277 VDPMMesh::VertexVertexIter vv_it;
278 VHierarchyNodeHandle nnode_handle;
279
280 VHierarchyNodeIndex
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 //=============================================================================
OpenMesh::VDPM::VHierarchyNode::lchild_handle
VHierarchyNodeHandle lchild_handle()
Returns handle to left child.
Definition: VHierarchyNode.hh:108
OpenMesh::VertexHandle
Handle for a vertex entity.
Definition: Handles.hh:120
OpenMesh::VDPM::VHierarchyNode::rchild_handle
VHierarchyNodeHandle rchild_handle()
Returns handle to right child.
Definition: VHierarchyNode.hh:111
OpenMesh::PolyMeshT::Point
Kernel::Point Point
Coordinate type.
Definition: PolyMeshT.hh:112
OpenMesh::PolyMeshT::add_vertex
VertexHandle add_vertex(const Point &_p)
Alias for new_vertex(const Point&).
Definition: PolyMeshT.hh:235
MeshViewerWidgetT< MyMesh >::draw_scene
virtual void draw_scene(const std::string &_draw_mode)
inherited drawing method
Definition: MeshViewerWidgetT_impl.hh:573
OpenMesh::TriMeshT::vertex_split
HalfedgeHandle vertex_split(Point _v0_point, VertexHandle _v1, VertexHandle _vl, VertexHandle _vr)
Vertex Split: inverse operation to collapse().
Definition: TriMeshT.hh:214
OpenMesh::PolyMeshT::VertexHandle
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Definition: PolyMeshT.hh:136
OpenMesh::VDPM::VHierarchyNodeHandle
Definition: VHierarchyNode.hh:77
OpenMesh::PolyMeshT::VertexVertexIter
Kernel::VertexVertexIter VertexVertexIter
Circulator.
Definition: PolyMeshT.hh:162
Timer.hh
OpenMesh::VDPM::Plane3d
Definition: Plane3d.hh:78
MeshViewerWidget
Definition: MeshViewerWidget.hh:75
OpenMesh::VectorT::length
auto length() const -> decltype(std::declval< VectorT< S, DIM >>().norm())
compute squared euclidean norm
Definition: Vector11T.hh:418
OpenMesh::VDPM::VHierarchyNodeIndex
Definition: VHierarchyNodeIndex.hh:73
OpenMesh::VectorT< float, 3 >
OpenMesh::PolyMeshT::update_face_normals
void update_face_normals()
Update normal vectors for all faces.
Definition: PolyMeshT_impl.hh:277
OpenMesh::VDPM::VHierarchyNode
Definition: VHierarchyNode.hh:90
OpenMesh
Definition: MeshItems.hh:59