/*===========================================================================*\ * * * OpenMesh * * Copyright (C) 2001-2012 by Computer Graphics Group, RWTH Aachen * * www.openmesh.org * * * *---------------------------------------------------------------------------* * This file is part of OpenMesh. * * * * OpenMesh is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 3 of * * the License, or (at your option) any later version with the * * following exceptions: * * * * If other files instantiate templates or use macros * * or inline functions from this file, or you compile this file and * * link it with other files to produce an executable, this file does * * not by itself cause the resulting executable to be covered by the * * GNU Lesser General Public License. This exception does not however * * invalidate any other reasons why the executable file might be * * covered by the GNU Lesser General Public License. * * * * OpenMesh is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU LesserGeneral Public * * License along with OpenMesh. If not, * * see . * * * \*===========================================================================*/ /*===========================================================================*\ * * * $Revision$ * * $Date$ * * * \*===========================================================================*/ //============================================================================= // // CLASS newClass - IMPLEMENTATION // //============================================================================= //== INCLUDES ================================================================= #ifdef _MSC_VER # pragma warning(disable: 4267 4311) #endif #include #include #include #include #include #include #include #ifdef ARCH_DARWIN #include #else #include #endif #include #include #include #include #include //== NAMESPACES =============================================================== namespace OpenMesh { //== IMPLEMENTATION ========================================================== VDPMSynthesizerViewerWidget::VDPMSynthesizerViewerWidget(QWidget* _parent, const char* _name) : MeshViewerWidget(_parent) { adaptive_mode_ = true; } VDPMSynthesizerViewerWidget::~VDPMSynthesizerViewerWidget() { } void VDPMSynthesizerViewerWidget:: draw_scene(const std::string &_draw_mode) { if (adaptive_mode_ == true) { adaptive_refinement(); } MeshViewerWidget::draw_scene(_draw_mode); } void VDPMSynthesizerViewerWidget:: adaptive_refinement() { update_viewing_parameters(); VDPMMesh::HalfedgeHandle v0v1; float fovy = viewing_parameters_.fovy(); float tolerance_square = viewing_parameters_.tolerance_square(); float tan_value = tanf(fovy / 2.0f); kappa_square_ = 4.0f * tan_value * tan_value * tolerance_square; //assert( !vfront_.end() ); for ( vfront_.begin(); !vfront_.end(); ) { VHierarchyNodeHandle node_handle = vfront_.node_handle(), parent_handle = vhierarchy_.parent_handle(node_handle); if (vhierarchy_.is_leaf_node(node_handle) != true && qrefine(node_handle) == true) { force_vsplit(node_handle); } else if (vhierarchy_.is_root_node(node_handle) != true && ecol_legal(parent_handle, v0v1) == true && qrefine(parent_handle) != true) { ecol(parent_handle, v0v1); } else { vfront_.next(); } } // free memories tagged as 'deleted' mesh_.garbage_collection(false, true, true); mesh_.update_face_normals(); } bool VDPMSynthesizerViewerWidget:: qrefine(VHierarchyNodeHandle _node_handle) { VHierarchyNode &node = vhierarchy_.node(_node_handle); Vec3f p = mesh_.point(node.vertex_handle()); Vec3f eye_dir = p - viewing_parameters_.eye_pos();; float distance = eye_dir.length(); float distance2 = distance * distance; float product_value = dot(eye_dir, node.normal()); if (outside_view_frustum(p, node.radius()) == true) return false; if (oriented_away(node.sin_square(), distance2, product_value) == true) return false; if (screen_space_error(node.mue_square(), node.sigma_square(), distance2, product_value) == true) return false; return true; } void VDPMSynthesizerViewerWidget:: force_vsplit(VHierarchyNodeHandle node_handle) { VDPMMesh::VertexHandle vl, vr; get_active_cuts(node_handle, vl, vr); while (vl == vr) { force_vsplit(mesh_.data(vl).vhierarchy_node_handle()); get_active_cuts(node_handle, vl, vr); } vsplit(node_handle, vl, vr); } void VDPMSynthesizerViewerWidget:: vsplit(VHierarchyNodeHandle _node_handle, VDPMMesh::VertexHandle vl, VDPMMesh::VertexHandle vr) { // refine VHierarchyNodeHandle lchild_handle = vhierarchy_.lchild_handle(_node_handle), rchild_handle = vhierarchy_.rchild_handle(_node_handle); VDPMMesh::VertexHandle v0 = vhierarchy_.vertex_handle(lchild_handle); VDPMMesh::VertexHandle v1 = vhierarchy_.vertex_handle(rchild_handle); mesh_.vertex_split(v0, v1, vl, vr); mesh_.set_normal(v0, vhierarchy_.normal(lchild_handle)); mesh_.set_normal(v1, vhierarchy_.normal(rchild_handle)); mesh_.data(v0).set_vhierarchy_node_handle(lchild_handle); mesh_.data(v1).set_vhierarchy_node_handle(rchild_handle); mesh_.status(v0).set_deleted(false); mesh_.status(v1).set_deleted(false); vfront_.remove(_node_handle); vfront_.add(lchild_handle); vfront_.add(rchild_handle); } void VDPMSynthesizerViewerWidget:: ecol(VHierarchyNodeHandle _node_handle, const VDPMMesh::HalfedgeHandle& v0v1) { VHierarchyNodeHandle lchild_handle = vhierarchy_.lchild_handle(_node_handle), rchild_handle = vhierarchy_.rchild_handle(_node_handle); VDPMMesh::VertexHandle v0 = vhierarchy_.vertex_handle(lchild_handle); VDPMMesh::VertexHandle v1 = vhierarchy_.vertex_handle(rchild_handle); // coarsen mesh_.collapse(v0v1); mesh_.set_normal(v1, vhierarchy_.normal(_node_handle)); mesh_.data(v0).set_vhierarchy_node_handle(lchild_handle); mesh_.data(v1).set_vhierarchy_node_handle(_node_handle); mesh_.status(v0).set_deleted(false); mesh_.status(v1).set_deleted(false); vfront_.add(_node_handle); vfront_.remove(lchild_handle); vfront_.remove(rchild_handle); } bool VDPMSynthesizerViewerWidget:: ecol_legal(VHierarchyNodeHandle _parent_handle, VDPMMesh::HalfedgeHandle& v0v1) { VHierarchyNodeHandle lchild_handle = vhierarchy_.lchild_handle(_parent_handle), rchild_handle = vhierarchy_.rchild_handle(_parent_handle); // test whether lchild & rchild present in the current vfront if ( vfront_.is_active(lchild_handle) != true || vfront_.is_active(rchild_handle) != true) return false; VDPMMesh::VertexHandle v0, v1; v0 = vhierarchy_.vertex_handle(lchild_handle); v1 = vhierarchy_.vertex_handle(rchild_handle); v0v1 = mesh_.find_halfedge(v0, v1); return mesh_.is_collapse_ok(v0v1); } void VDPMSynthesizerViewerWidget:: get_active_cuts(const VHierarchyNodeHandle _node_handle, VDPMMesh::VertexHandle &vl, VDPMMesh::VertexHandle &vr) { VDPMMesh::VertexVertexIter vv_it; VHierarchyNodeHandle nnode_handle; VHierarchyNodeIndex nnode_index, fund_lcut_index = vhierarchy_.fund_lcut_index(_node_handle), fund_rcut_index = vhierarchy_.fund_rcut_index(_node_handle); vl = VDPMMesh::InvalidVertexHandle; vr = VDPMMesh::InvalidVertexHandle; for (vv_it=mesh_.vv_iter(vhierarchy_.vertex_handle(_node_handle)); vv_it; ++vv_it) { nnode_handle = mesh_.data(vv_it.handle()).vhierarchy_node_handle(); nnode_index = vhierarchy_.node_index(nnode_handle); if (vl == VDPMMesh::InvalidVertexHandle && vhierarchy_.is_ancestor(nnode_index, fund_lcut_index) == true) vl = vv_it.handle(); if (vr == VDPMMesh::InvalidVertexHandle && vhierarchy_.is_ancestor(nnode_index, fund_rcut_index) == true) vr = vv_it.handle(); /*if (vl == VDPMMesh::InvalidVertexHandle && nnode_index.is_ancestor_index(fund_lcut_index) == true) vl = vv_it.handle(); if (vr == VDPMMesh::InvalidVertexHandle && nnode_index.is_ancestor_index(fund_rcut_index) == true) vr = vv_it.handle();*/ if (vl != VDPMMesh::InvalidVertexHandle && vr != VDPMMesh::InvalidVertexHandle) break; } } bool VDPMSynthesizerViewerWidget:: outside_view_frustum(const Vec3f &pos, float radius) { #if 0 return (frustum_plane_[0].signed_distance(pos) < -radius) || (frustum_plane_[1].signed_distance(pos) < -radius) || (frustum_plane_[2].signed_distance(pos) < -radius) || (frustum_plane_[3].signed_distance(pos) < -radius); #else Plane3d frustum_plane[4]; viewing_parameters_.frustum_planes(frustum_plane); for (int i = 0; i < 4; i++) { if (frustum_plane[i].singed_distance(pos) < -radius) return true; } return false; #endif } bool VDPMSynthesizerViewerWidget:: oriented_away(float sin_square, float distance_square, float product_value) { #if 0 return (product_value > 0) && ((product_value * product_value) > (distance_square * sin_square)); #else if (product_value > 0 && product_value * product_value > distance_square * sin_square) return true; else return false; #endif } bool VDPMSynthesizerViewerWidget:: screen_space_error(float mue_square, float sigma_square, float distance_square, float product_value) { #if 0 float ks_ds = kappa_square_ * distance_square; float pv_pv = product_value * product_value; return (mue_square >= ks_ds) || (sigma_square*( distance_square - pv_pv) >= ks_ds*distance_square); #else if ((mue_square >= kappa_square_ * distance_square) || (sigma_square * (distance_square - product_value * product_value) >= kappa_square_ * distance_square * distance_square)) return false; else return true; #endif } void VDPMSynthesizerViewerWidget:: open_vd_prog_mesh(const char* _filename) { unsigned int i; unsigned int value; unsigned int fvi[3]; char fileformat[16]; Vec3f p, normal; float radius, sin_square, mue_square, sigma_square; VHierarchyNodeHandleContainer roots; VertexHandle vertex_handle; VHierarchyNodeIndex node_index; VHierarchyNodeIndex lchild_node_index, rchild_node_index; VHierarchyNodeIndex fund_lcut_index, fund_rcut_index; VHierarchyNodeHandle node_handle; VHierarchyNodeHandle lchild_node_handle, rchild_node_handle; std::map index2handle_map; std::ifstream ifs(_filename, std::ios::binary); if (!ifs) { std::cerr << "read error\n"; exit(1); } // bool swap = Endian::local() != Endian::LSB; // read header ifs.read(fileformat, 10); fileformat[10] = '\0'; if (std::string(fileformat) != std::string("VDProgMesh")) { std::cerr << "Wrong file format.\n"; ifs.close(); exit(1); } IO::restore(ifs, n_base_vertices_, swap); IO::restore(ifs, n_base_faces_, swap); IO::restore(ifs, n_details_, swap); mesh_.clear(); vfront_.clear(); vhierarchy_.clear(); vhierarchy_.set_num_roots(n_base_vertices_); // load base mesh for (i=0; ikey()) { case Key_Home: updateGL(); break; case Key_End: updateGL(); break; case Key_Minus: viewing_parameters_.increase_tolerance(); std::cout << "Scree-space error tolerance^2 is increased by " << viewing_parameters_.tolerance_square() << std::endl; updateGL(); break; case Key_Plus: viewing_parameters_.decrease_tolerance(); std::cout << "Screen-space error tolerance^2 is decreased by " << viewing_parameters_.tolerance_square() << std::endl; updateGL(); break; case Key_A: adaptive_mode_ = !(adaptive_mode_); std::cout << "Adaptive refinement mode is " << (adaptive_mode_ ? "on" : "off") << std::endl; updateGL(); break; case Key_O: qFilename_ = QFileDialog::getOpenFileName(0,"", "", "*.spm"); open_vd_prog_mesh( qFilename_.toStdString().c_str() ); break; default: MeshViewerWidget::keyPressEvent( _event ); } } void VDPMSynthesizerViewerWidget:: update_viewing_parameters() { viewing_parameters_.set_modelview_matrix(modelview_matrix()); viewing_parameters_.set_aspect((float) width()/ (float) height()); viewing_parameters_.set_fovy(fovy()); viewing_parameters_.update_viewing_configurations(); } //============================================================================= } // namespace OpenMesh //=============================================================================