Developer Documentation
Loading...
Searching...
No Matches
VDPMSynthesizerViewerWidget.cc
1/* ========================================================================= *
2 * *
3 * OpenMesh *
4 * Copyright (c) 2001-2025, 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
75namespace OpenMesh {
76
77
78//== IMPLEMENTATION ==========================================================
79
80VDPMSynthesizerViewerWidget::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
93VDPMSynthesizerViewerWidget::~VDPMSynthesizerViewerWidget()
94{
95
96}
97
98void
99VDPMSynthesizerViewerWidget::
100draw_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
110void
111VDPMSynthesizerViewerWidget::
112adaptive_refinement()
113{
114 update_viewing_parameters();
115
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
156bool
157VDPMSynthesizerViewerWidget::
158qrefine(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
184void
185VDPMSynthesizerViewerWidget::
186force_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
203void
204VDPMSynthesizerViewerWidget::
205vsplit(VHierarchyNodeHandle _node_handle,
206 VDPMMesh::VertexHandle vl,
207 VDPMMesh::VertexHandle vr)
208{
209 // refine
210 VHierarchyNodeHandle
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
231void
232VDPMSynthesizerViewerWidget::
233ecol(VHierarchyNodeHandle _node_handle, const VDPMMesh::HalfedgeHandle& v0v1)
234{
235 VHierarchyNodeHandle
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
256bool
257VDPMSynthesizerViewerWidget::
258ecol_legal(VHierarchyNodeHandle _parent_handle, VDPMMesh::HalfedgeHandle& v0v1)
259{
260 VHierarchyNodeHandle
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
279void
280VDPMSynthesizerViewerWidget::
281get_active_cuts(const VHierarchyNodeHandle _node_handle,
282 VDPMMesh::VertexHandle &vl, VDPMMesh::VertexHandle &vr)
283{
284 VDPMMesh::VertexVertexIter vv_it;
285 VHierarchyNodeHandle nnode_handle;
286
287 VHierarchyNodeIndex
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
321bool
322VDPMSynthesizerViewerWidget::
323outside_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
345bool
346VDPMSynthesizerViewerWidget::
347oriented_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
362bool
363VDPMSynthesizerViewerWidget::
364screen_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
381void
382VDPMSynthesizerViewerWidget::
383open_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_required = 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_required);
422 IO::restore(ifs, n_base_faces_, swap_required);
423 IO::restore(ifs, n_details_, swap_required);
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_required);
435 IO::restore(ifs, radius, swap_required);
436 IO::restore(ifs, normal, swap_required);
437 IO::restore(ifs, sin_square, swap_required);
438 IO::restore(ifs, mue_square, swap_required);
439 IO::restore(ifs, sigma_square, swap_required);
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_required);
466 IO::restore(ifs, fvi[1], swap_required);
467 IO::restore(ifs, fvi[2], swap_required);
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_required);
479
480 // vsplit info.
481 IO::restore(ifs, value, swap_required);
482 node_index = VHierarchyNodeIndex(value);
483
484 IO::restore(ifs, value, swap_required);
485 fund_lcut_index = VHierarchyNodeIndex(value);
486
487 IO::restore(ifs, value, swap_required);
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_required);
510 IO::restore(ifs, normal, swap_required);
511 IO::restore(ifs, sin_square, swap_required);
512 IO::restore(ifs, mue_square, swap_required);
513 IO::restore(ifs, sigma_square, swap_required);
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_required);
521 IO::restore(ifs, normal, swap_required);
522 IO::restore(ifs, sin_square, swap_required);
523 IO::restore(ifs, mue_square, swap_required);
524 IO::restore(ifs, sigma_square, swap_required);
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
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
564void 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
612void
613VDPMSynthesizerViewerWidget::
614update_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//=============================================================================
void update_face_normals()
Update normal vectors for all faces.
SmartVertexHandle add_vertex(const Point _p)
Definition PolyMeshT.hh:255
Kernel::HalfedgeHandle HalfedgeHandle
Scalar type.
Definition PolyMeshT.hh:137
Kernel::ConstVertexIter ConstVertexIter
Scalar type.
Definition PolyMeshT.hh:148
Kernel::Point Point
Coordinate type.
Definition PolyMeshT.hh:112
HalfedgeHandle vertex_split(Point _v0_point, VertexHandle _v1, VertexHandle _vl, VertexHandle _vr)
Vertex Split: inverse operation to collapse().
Definition TriMeshT.hh:218
VHierarchyNodeHandle rchild_handle()
Returns handle to right child.
VHierarchyNodeHandle lchild_handle()
Returns handle to left child.
auto length() const -> decltype(std::declval< VectorT< S, DIM > >().norm())
compute squared euclidean norm
Definition Vector11T.hh:443
DLLEXPORT double fovy(int _viewer)
Get field of view angle.
Handle for a vertex entity.
Definition Handles.hh:121