55#include <OpenMesh/Core/IO/MeshIO.hh>
56#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
57#include <OpenMesh/Core/Utils/Endian.hh>
59#include <OpenMesh/Tools/Utils/getopt.h>
61#include <OpenMesh/Tools/VDPM/StreamingDef.hh>
62#include <OpenMesh/Tools/VDPM/ViewingParameters.hh>
63#include <OpenMesh/Tools/VDPM/VHierarchy.hh>
64#include <OpenMesh/Tools/VDPM/VFront.hh>
96 {
return node_handle_; }
99 { node_handle_ = _node_handle; }
116 vhierarchy_leaf_node_handle()
117 {
return leaf_node_handle_; }
121 { leaf_node_handle_ = _leaf_node_handle; }
148typedef std::vector<PMInfo> PMInfoContainer;
149typedef PMInfoContainer::iterator PMInfoIter;
150typedef std::vector<VertexHandle> VertexHandleContainer;
151typedef std::vector<Vec3f> ResidualContainer;
157void open_prog_mesh(
const std::string &_filename);
160void save_vd_prog_mesh(
const std::string &_filename);
164void locate_fund_cut_vertices();
166void create_vertex_hierarchy();
170void refine(
unsigned int _n);
173void coarsen(
unsigned int _n);
178 VHierarchyNodeHandleContainer &leaf_nodes);
180 VHierarchyNodeHandleContainer &leaf_nodes);
182 VHierarchyNodeHandleContainer &leaf_nodes);
184 VHierarchyNodeHandleContainer &leaf_nodes);
186 ResidualContainer &residuals);
189point2triangle_residual(
const Vec3f &p,
190 const Vec3f tri[3],
float &s,
float &t);
193void PrintOutFundCuts();
194void PrintVertexNormals();
200PMInfoContainer pminfos_;
205unsigned int n_base_vertices_, n_base_faces_, n_details_;
206unsigned int n_current_res_;
207unsigned int n_max_res_;
213void usage_and_exit(
int xcode)
217 cout <<
"Usage: vdpmanalyzer [-h] [-o output.spm] input.pm\n";
226replace_extension( std::string& _s,
const std::string& _e )
228 std::string::size_type
dot = _s.rfind(
".");
229 if (
dot == std::string::npos)
233 const std::string temp_name = _s.substr(0,
dot+1);
243basename(
const std::string& _f)
245 std::string::size_type
dot = _f.rfind(
"/");
246 if (
dot == std::string::npos)
248 return _f.substr(
dot+1, _f.length()-(
dot+1));
255typedef std::vector<OpenMesh::Vec3f> MyPoints;
256typedef MyPoints::iterator MyPointsIter;
258MyPoints projected_points;
259MyPoints original_points;
265int main(
int argc,
char **argv)
271 while ( (c=getopt(argc, argv,
"o:"))!=-1 )
275 case 'v': verbose =
true;
break;
276 case 'o': ofname = optarg;
break;
277 case 'h': usage_and_exit(0);
break;
278 default: usage_and_exit(1);
285 ifname = argv[optind];
287 if (ofname ==
"." || ofname ==
".." )
288 ofname +=
"/" + basename(ifname);
289 std::string spmfname = ofname.empty() ? ifname : ofname;
290 replace_extension(spmfname,
"spm");
292 if ( ifname.empty() || spmfname.empty() )
299 open_prog_mesh(ifname);
301 save_vd_prog_mesh(spmfname);
303 catch( std::bad_alloc& )
305 std::cerr <<
"Error: out of memory!\n" << std::endl;
308 catch( std::exception& x )
310 std::cerr <<
"Error: " << x.what() << std::endl;
315 std::cerr <<
"Fatal! Unknown error!\n";
325open_prog_mesh(
const std::string& _filename)
328 unsigned int i, i0, i1, i2;
329 unsigned int v1, vl, vr;
335 std::ifstream ifs(_filename.c_str(), std::ios::binary);
338 std::cerr <<
"read error\n";
343 bool swap = Endian::local() != Endian::LSB;
346 ifs.read(c, 8); c[8] =
'\0';
347 if (std::string(c) != std::string(
"ProgMesh"))
349 std::cerr <<
"Wrong file format.\n";
353 IO::restore(ifs, n_base_vertices_,
swap);
354 IO::restore(ifs, n_base_faces_,
swap);
355 IO::restore(ifs, n_details_,
swap);
357 vhierarchy_.set_num_roots(n_base_vertices_);
359 for (i=0; i<n_base_vertices_; ++i)
361 IO::restore(ifs, p,
swap);
364 node_index = vhierarchy_.generate_node_index(i, 1);
365 node_handle = vhierarchy_.add_node();
367 vhierarchy_.node(node_handle).set_index(node_index);
368 vhierarchy_.node(node_handle).set_vertex_handle(vertex_handle);
369 mesh_.data(vertex_handle).set_vhierarchy_node_handle(node_handle);
372 for (i=0; i<n_base_faces_; ++i)
374 IO::restore(ifs, i0,
swap);
375 IO::restore(ifs, i1,
swap);
376 IO::restore(ifs, i2,
swap);
377 mesh_.add_face(mesh_.vertex_handle(i0),
378 mesh_.vertex_handle(i1),
379 mesh_.vertex_handle(i2));
383 for (i=0; i<n_details_; ++i)
385 IO::restore(ifs, p,
swap);
386 IO::restore(ifs, v1,
swap);
387 IO::restore(ifs, vl,
swap);
388 IO::restore(ifs, vr,
swap);
396 pminfos_.push_back(pminfo);
398 node_handle = mesh_.data(pminfo.v1).vhierarchy_node_handle();
400 vhierarchy_.make_children(node_handle);
401 lchild_handle = vhierarchy_.lchild_handle(node_handle);
402 rchild_handle = vhierarchy_.rchild_handle(node_handle);
404 mesh_.data(pminfo.v0).set_vhierarchy_node_handle(lchild_handle);
405 mesh_.data(pminfo.v1).set_vhierarchy_node_handle(rchild_handle);
406 vhierarchy_.node(lchild_handle).set_vertex_handle(pminfo.v0);
407 vhierarchy_.node(rchild_handle).set_vertex_handle(pminfo.v1);
414 for (i=0; i<n_base_vertices_; ++i)
416 node_handle = vhierarchy_.root_handle(i);
417 vertex_handle = vhierarchy_.node(node_handle).vertex_handle();
419 mesh_.data(vertex_handle).set_vhierarchy_node_handle(node_handle);
422 pmiter_ = pminfos_.begin();
424 n_max_res_ = n_details_;
433 vIt(mesh_.vertices_begin()),
434 vEnd(mesh_.vertices_end());
438 bbMin = bbMax = mesh_.point(*vIt);
439 for (; vIt!=vEnd; ++vIt)
441 bbMin.minimize(mesh_.point(*vIt));
442 bbMax.maximize(mesh_.point(*vIt));
446 std::cerr << mesh_.n_vertices() <<
" vertices, "
447 << mesh_.n_edges() <<
" edge, "
448 << mesh_.n_faces() <<
" faces, "
449 << n_details_ <<
" detail vertices\n";
456save_vd_prog_mesh(
const std::string &_filename)
462 float radius, sin_square, mue_square, sigma_square;
469 std::map<VertexHandle, unsigned int> handle2index_map;
471 std::ofstream ofs(_filename.c_str(), std::ios::binary);
474 std::cerr <<
"write error\n";
479 bool swap = Endian::local() != Endian::LSB;
484 IO::store(ofs, n_base_vertices_,
swap);
485 IO::store(ofs, n_base_faces_,
swap);
486 IO::store(ofs, n_details_,
swap);
490 mesh_.garbage_collection(
false,
true,
true );
492 for (i=0; i<n_base_vertices_; ++i)
494 node_handle = vhierarchy_.root_handle(i);
495 vh = vhierarchy_.node(node_handle).vertex_handle();
498 radius = vhierarchy_.node(node_handle).radius();
499 normal = vhierarchy_.node(node_handle).normal();
500 sin_square = vhierarchy_.node(node_handle).sin_square();
501 mue_square = vhierarchy_.node(node_handle).mue_square();
502 sigma_square = vhierarchy_.node(node_handle).sigma_square();
504 IO::store(ofs, p,
swap);
505 IO::store(ofs, radius,
swap);
506 IO::store(ofs, normal,
swap);
507 IO::store(ofs, sin_square,
swap);
508 IO::store(ofs, mue_square,
swap);
509 IO::store(ofs, sigma_square,
swap);
511 handle2index_map[vh] = i;
515 for (f_it=mesh_.faces_begin(); f_it!=mesh_.faces_end(); ++f_it) {
516 hh = mesh_.halfedge_handle(*f_it);
517 vh = mesh_.to_vertex_handle(hh);
518 fvi[0] = handle2index_map[vh];
520 hh = mesh_.next_halfedge_handle(hh);
521 vh = mesh_.to_vertex_handle(hh);
522 fvi[1] = handle2index_map[vh];
524 hh = mesh_.next_halfedge_handle(hh);
525 vh = mesh_.to_vertex_handle(hh);
526 fvi[2] = handle2index_map[vh];
528 IO::store(ofs, fvi[0],
swap);
529 IO::store(ofs, fvi[1],
swap);
530 IO::store(ofs, fvi[2],
swap);
536 for (i=0; i<n_details_; ++i)
538 PMInfo pminfo = *pmiter_;
540 p = mesh_.point(pminfo.v0);
542 IO::store(ofs, p,
swap);
545 node_handle = mesh_.data(pminfo.v1).vhierarchy_node_handle();
546 lchild_handle = vhierarchy_.lchild_handle(node_handle);
547 rchild_handle = vhierarchy_.rchild_handle(node_handle);
549 node_index = vhierarchy_.node(node_handle).node_index();
550 fund_lcut_index = vhierarchy_.node(node_handle).fund_lcut_index();
551 fund_rcut_index = vhierarchy_.node(node_handle).fund_rcut_index();
553 IO::store(ofs, node_index.value(),
swap);
554 IO::store(ofs, fund_lcut_index.value(),
swap);
555 IO::store(ofs, fund_rcut_index.value(),
swap);
557 radius = vhierarchy_.node(lchild_handle).radius();
558 normal = vhierarchy_.node(lchild_handle).normal();
559 sin_square = vhierarchy_.node(lchild_handle).sin_square();
560 mue_square = vhierarchy_.node(lchild_handle).mue_square();
561 sigma_square = vhierarchy_.node(lchild_handle).sigma_square();
563 IO::store(ofs, radius,
swap);
564 IO::store(ofs, normal,
swap);
565 IO::store(ofs, sin_square,
swap);
566 IO::store(ofs, mue_square,
swap);
567 IO::store(ofs, sigma_square,
swap);
569 radius = vhierarchy_.node(rchild_handle).radius();
570 normal = vhierarchy_.node(rchild_handle).normal();
571 sin_square = vhierarchy_.node(rchild_handle).sin_square();
572 mue_square = vhierarchy_.node(rchild_handle).mue_square();
573 sigma_square = vhierarchy_.node(rchild_handle).sigma_square();
575 IO::store(ofs, radius,
swap);
576 IO::store(ofs, normal,
swap);
577 IO::store(ofs, sin_square,
swap);
578 IO::store(ofs, mue_square,
swap);
579 IO::store(ofs, sigma_square,
swap);
586 std::cout <<
"save view-dependent progressive mesh" << std::endl;
591void refine(
unsigned int _n)
593 while (n_current_res_ < _n && pmiter_ != pminfos_.end())
601 parent_handle = mesh_.data(pmiter_->v1).vhierarchy_node_handle();
604 lchild_handle = vhierarchy_.lchild_handle(parent_handle),
605 rchild_handle = vhierarchy_.rchild_handle(parent_handle);
607 mesh_.data(pmiter_->v0).set_vhierarchy_node_handle(lchild_handle);
608 mesh_.data(pmiter_->v1).set_vhierarchy_node_handle(rchild_handle);
619void coarsen(
unsigned int _n)
621 while (n_current_res_ > _n && pmiter_ != pminfos_.begin())
626 mesh_.find_halfedge(pmiter_->v0, pmiter_->v1);
630 rchild_handle = mesh_.data(pmiter_->v1).vhierarchy_node_handle();
633 parent_handle = vhierarchy_.parent_handle(rchild_handle);
635 mesh_.data(pmiter_->v1).set_vhierarchy_node_handle(parent_handle);
663 std::cout <<
"Init view-dependent PM analysis" << std::endl;
666 for (h_it=mesh_.halfedges_begin(); h_it!=mesh_.halfedges_end(); ++h_it)
668 vh = mesh_.to_vertex_handle(*h_it);
669 mesh_.data(*h_it).set_vhierarchy_leaf_node_handle(mesh_.data(vh).vhierarchy_node_handle());
672 for (v_it=mesh_.vertices_begin(); v_it!=mesh_.vertices_end(); ++v_it)
675 node_handle = mesh_.data(*v_it).vhierarchy_node_handle();
677 vhierarchy_.node(node_handle).set_normal(mesh_.normal(*v_it));
680 std::cout <<
"Start view-dependent PM analysis" << std::endl;
685 for (i=n_max_res_; i>0; --i)
688 PMInfo pminfo = pminfos_[i-1];
691 std::cout <<
"Analyzing " << i <<
"-th detail vertex" << std::endl;
694 h = mesh_.find_halfedge(pminfo.v0, pminfo.v1);
695 o = mesh_.opposite_halfedge_handle(h);
696 hn = mesh_.next_halfedge_handle(h);
697 hpo = mesh_.opposite_halfedge_handle(mesh_.prev_halfedge_handle(h));
698 op = mesh_.prev_halfedge_handle(o);
699 on = mesh_.next_halfedge_handle(o);
700 ono = mesh_.opposite_halfedge_handle(on);
703 rchild_handle = mesh_.data(pminfo.v1).vhierarchy_node_handle();
706 parent_handle = vhierarchy_.parent_handle(rchild_handle);
708 if (pminfo.vl != Mesh::InvalidVertexHandle)
711 fund_lcut_handle = mesh_.data(hn).vhierarchy_leaf_node_handle();
714 left_leaf_handle = mesh_.data(hpo).vhierarchy_leaf_node_handle();
716 mesh_.data(hn).set_vhierarchy_leaf_node_handle(left_leaf_handle);
718 vhierarchy_.node(parent_handle).
719 set_fund_lcut(vhierarchy_.node_index(fund_lcut_handle));
722 if (pminfo.vr != Mesh::InvalidVertexHandle)
725 fund_rcut_handle = mesh_.data(on).vhierarchy_leaf_node_handle(),
726 right_leaf_handle = mesh_.data(ono).vhierarchy_leaf_node_handle();
728 mesh_.data(op).set_vhierarchy_leaf_node_handle(right_leaf_handle);
730 vhierarchy_.node(parent_handle).
731 set_fund_rcut(vhierarchy_.node_index(fund_rcut_handle));
738 get_leaf_node_handles(parent_handle, leaf_nodes);
739 compute_bounding_box(parent_handle, leaf_nodes);
740 compute_cone_of_normals(parent_handle, leaf_nodes);
741 compute_screen_space_error(parent_handle, leaf_nodes);
747 std::cout <<
" radius of bounding sphere: "
748 << vhierarchy_.node(parent_handle).radius() << std::endl;
749 std::cout <<
" direction of cone of normals: "
750 << vhierarchy_.node(parent_handle).normal() << std::endl;
751 std::cout <<
" sin(semi-angle of cone of normals) ^2: "
752 << vhierarchy_.node(parent_handle).sin_square() << std::endl;
753 std::cout <<
" (mue^2, sigma^2) : ("
754 << vhierarchy_.node(parent_handle).mue_square() <<
", "
755 << vhierarchy_.node(parent_handle).sigma_square() <<
")"
757 std::cout <<
"- " << t.
as_string() << std::endl;
763 std::cout <<
"Analyzing step completed in "
772 VHierarchyNodeHandleContainer &leaf_nodes)
774 if (vhierarchy_.node(node_handle).
is_leaf())
776 leaf_nodes.push_back(node_handle);
780 get_leaf_node_handles(vhierarchy_.node(node_handle).
lchild_handle(),
782 get_leaf_node_handles(vhierarchy_.node(node_handle).
rchild_handle(),
791compute_bounding_box(
VHierarchyNodeHandle node_handle, VHierarchyNodeHandleContainer &leaf_nodes)
795 VHierarchyNodeHandleContainer::iterator n_it, n_end(leaf_nodes.end());
798 VertexHandle vh = vhierarchy_.node(node_handle).vertex_handle();
800 for ( n_it = leaf_nodes.begin(); n_it != n_end; ++n_it )
802 lp = mesh_.point(vhierarchy_.vertex_handle(*n_it));
803 max_distance = std::max(max_distance, (p - lp).length());
806 vhierarchy_.node(node_handle).set_radius(max_distance);
814 VHierarchyNodeHandleContainer &leaf_nodes)
817 VertexHandle vh = vhierarchy_.node(node_handle).vertex_handle();
818 VHierarchyNodeHandleContainer::iterator n_it, n_end(leaf_nodes.end());
821 float max_angle = 0.0f;
823 n_it = leaf_nodes.begin();
824 while( n_it != n_end )
826 ln = vhierarchy_.node(*n_it).normal();
827 const float angle = acosf(
dot(n,ln) );
828 max_angle = std::max(max_angle, angle );
833 max_angle = std::min(max_angle,
float(M_PI_2));
834 mesh_.set_normal(vh, n);
835 vhierarchy_.node(node_handle).set_normal(n);
836 vhierarchy_.node(node_handle).set_semi_angle(max_angle);
843compute_screen_space_error(
VHierarchyNodeHandle node_handle, VHierarchyNodeHandleContainer &leaf_nodes)
845 std::vector<Vec3f> residuals;
852#if ((defined(_MSC_VER) && (_MSC_VER >= 1800)) )
854 Vec3f tri[3]{ {},{},{} };
859 VHierarchyNodeHandleContainer::iterator n_it, n_end(leaf_nodes.end());
861 for ( n_it = leaf_nodes.begin(); n_it != n_end; ++n_it )
863 lp = mesh_.point(vhierarchy_.node(*n_it).vertex_handle());
866 vh = vhierarchy_.node(node_handle).vertex_handle();
867 residual = lp - mesh_.point(vh);
868 float min_distance = residual.
length();
870 for (vf_it=mesh_.vf_iter(vh); vf_it.is_valid(); ++vf_it)
872 heh = mesh_.halfedge_handle(*vf_it);
873 tri[0] = mesh_.point(mesh_.to_vertex_handle(heh));
874 heh = mesh_.next_halfedge_handle(heh);
875 tri[1] = mesh_.point(mesh_.to_vertex_handle(heh));
876 heh = mesh_.next_halfedge_handle(heh);
877 tri[2] = mesh_.point(mesh_.to_vertex_handle(heh));
879 res = point2triangle_residual(lp, tri, s, t);
881 if (res.
length() < min_distance)
884 min_distance = res.
length();
888 residuals.push_back(residual);
891 compute_mue_sigma(node_handle, residuals);
899 ResidualContainer &residuals)
902 float max_inner, max_cross;
903 ResidualContainer::iterator r_it, r_end(residuals.end());
905 max_inner = max_cross = 0.0f;
906 vn = mesh_.normal(vhierarchy_.node(node_handle).vertex_handle());
907 for (r_it = residuals.begin(); r_it != r_end; ++r_it)
909 float inner = fabsf(
dot(*r_it, vn));
910 float cross = OpenMesh::cross(*r_it, vn).length();
912 max_inner = std::max(max_inner, inner);
913 max_cross = std::max(max_cross,
cross);
916 if (max_cross < 1.0e-7)
918 vhierarchy_.node(node_handle).set_mue(max_cross);
919 vhierarchy_.node(node_handle).set_sigma(max_inner);
922 float ratio = std::max(1.0f, max_inner/max_cross);
923 float whole_degree = acosf(1.0f/ratio);
928 for (r_it = residuals.begin(); r_it != r_end; ++r_it)
931 float res_length = res.
length();
934 float degree = acosf(
dot(vn,res) / res_length);
936 if (degree < 0.0f) degree = -degree;
937 if (degree >
float(M_PI_2)) degree = float(M_PI) - degree;
939 if (degree < whole_degree)
940 mue = cosf(whole_degree - degree) * res_length;
944 max_mue = std::max(max_mue, mue);
947 vhierarchy_.node(node_handle).set_mue(max_mue);
948 vhierarchy_.node(node_handle).set_sigma(ratio*max_mue);
956point2triangle_residual(
const Vec3f &p,
const Vec3f tri[3],
float &s,
float &t)
962 float a =
dot(E0, E0);
963 float b =
dot(E0, E1);
964 float c =
dot(E1, E1);
965 float d =
dot(E0, D);
966 float e =
dot(E1, D);
968 float det = fabsf(a*c - b*b);
1036 else if ( t < 0.0f )
1058 float inv_det = 1.0f/det;
1066 float tmp0, tmp1, numer, denom;
1074 numer = tmp1 - tmp0;
1076 if ( numer >= denom )
1097 else if ( e >= 0.0f )
1109 else if ( t < 0.0f )
1115 numer = tmp1 - tmp0;
1117 if ( numer >= denom )
1138 else if ( d >= 0.0f )
1152 numer = c + e - b - d;
1153 if ( numer <= 0.0f )
1162 if ( numer >= denom )
1178 residual = p - (B + s*E0 + t*E1);
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Kernel::VertexFaceIter VertexFaceIter
Circulator.
Kernel::FaceIter FaceIter
Scalar type.
void update_face_normals()
Update normal vectors for all faces.
SmartVertexHandle add_vertex(const Point _p)
Kernel::HalfedgeHandle HalfedgeHandle
Scalar type.
Kernel::ConstVertexIter ConstVertexIter
Scalar type.
void update_vertex_normals()
Update normal vectors for all vertices.
Kernel::HalfedgeIter HalfedgeIter
Scalar type.
Kernel::Point Point
Coordinate type.
Kernel::VertexIter VertexIter
Scalar type.
Normal calc_vertex_normal(VertexHandle _vh) const
Calculate vertex normal for one specific vertex.
HalfedgeHandle vertex_split(Point _v0_point, VertexHandle _v1, VertexHandle _vl, VertexHandle _vr)
Vertex Split: inverse operation to collapse().
void stop(void)
Stop measurement.
std::string as_string(Format format=Automatic)
void start(void)
Start measurement.
VHierarchyNodeHandle rchild_handle()
Returns handle to right child.
bool is_leaf() const
Returns true, if node is leaf else false.
VHierarchyNodeHandle lchild_handle()
Returns handle to left child.
Scalar dot(const VectorT< Scalar, DIM > &_v1, const VectorT< Scalar, DIM > &_v2)
auto cross(const VectorT< LScalar, DIM > &_v1, const VectorT< RScalar, DIM > &_v2) -> decltype(_v1 % _v2)
void swap(VectorT< Scalar, DIM > &_v1, VectorT< Scalar, DIM > &_v2) noexcept(noexcept(_v1.swap(_v2)))
auto length() const -> decltype(std::declval< VectorT< S, DIM > >().norm())
compute squared euclidean norm
@ Status
Add status to mesh item (all items)
@ PrevHalfedge
Add storage for previous halfedge (halfedges). The bit is set by default in the DefaultTraits.
std::vector< VHierarchyNodeHandle > VHierarchyNodeHandleContainer
Container for vertex hierarchy node handles.
T angle(T _cos_angle, T _sin_angle)
Handle for a vertex entity.