From f4a5512500717e377347867385167e94e8641eb8 Mon Sep 17 00:00:00 2001 From: ganovelli Date: Fri, 1 Apr 2011 17:16:29 +0000 Subject: [PATCH] Ongoing Rearrangement of filepath delete old trimesh content --- vcg/complex/trimesh/attribute_seam.h | 369 ----- vcg/complex/trimesh/autoalign_4pcs.h | 677 --------- vcg/complex/trimesh/bitquad_creation.h | 788 ---------- vcg/complex/trimesh/bitquad_optimization.h | 404 ------ vcg/complex/trimesh/bitquad_support.h | 1180 --------------- vcg/complex/trimesh/boundary.h | 160 -- vcg/complex/trimesh/clean.h | 1529 -------------------- vcg/complex/trimesh/clip.h | 1114 -------------- vcg/complex/trimesh/closest.h | 563 ------- vcg/complex/trimesh/clustering.h | 436 ------ vcg/complex/trimesh/crease_cut.h | 147 -- vcg/complex/trimesh/edge_collapse.h | 372 ----- vcg/complex/trimesh/geodesic.h | 393 ----- vcg/complex/trimesh/halfedge_quad_clean.h | 712 --------- vcg/complex/trimesh/hole.h | 992 ------------- vcg/complex/trimesh/inertia.h | 383 ----- vcg/complex/trimesh/inside.h | 115 -- vcg/complex/trimesh/intersection.h | 470 ------ vcg/complex/trimesh/local_optimization.h | 398 ----- vcg/complex/trimesh/nring.h | 157 -- vcg/complex/trimesh/overlap_estimation.h | 327 ----- vcg/complex/trimesh/point_sampling.h | 1468 ------------------- vcg/complex/trimesh/polygon_support.h | 178 --- vcg/complex/trimesh/refine.h | 924 ------------ vcg/complex/trimesh/refine_loop.h | 623 -------- vcg/complex/trimesh/smooth.h | 1331 ----------------- vcg/complex/trimesh/stat.h | 246 ---- vcg/complex/trimesh/subset.h | 171 --- 28 files changed, 16627 deletions(-) delete mode 100644 vcg/complex/trimesh/attribute_seam.h delete mode 100644 vcg/complex/trimesh/autoalign_4pcs.h delete mode 100644 vcg/complex/trimesh/bitquad_creation.h delete mode 100644 vcg/complex/trimesh/bitquad_optimization.h delete mode 100644 vcg/complex/trimesh/bitquad_support.h delete mode 100644 vcg/complex/trimesh/boundary.h delete mode 100644 vcg/complex/trimesh/clean.h delete mode 100644 vcg/complex/trimesh/clip.h delete mode 100644 vcg/complex/trimesh/closest.h delete mode 100644 vcg/complex/trimesh/clustering.h delete mode 100644 vcg/complex/trimesh/crease_cut.h delete mode 100644 vcg/complex/trimesh/edge_collapse.h delete mode 100644 vcg/complex/trimesh/geodesic.h delete mode 100755 vcg/complex/trimesh/halfedge_quad_clean.h delete mode 100644 vcg/complex/trimesh/hole.h delete mode 100644 vcg/complex/trimesh/inertia.h delete mode 100644 vcg/complex/trimesh/inside.h delete mode 100644 vcg/complex/trimesh/intersection.h delete mode 100644 vcg/complex/trimesh/local_optimization.h delete mode 100644 vcg/complex/trimesh/nring.h delete mode 100644 vcg/complex/trimesh/overlap_estimation.h delete mode 100644 vcg/complex/trimesh/point_sampling.h delete mode 100644 vcg/complex/trimesh/polygon_support.h delete mode 100644 vcg/complex/trimesh/refine.h delete mode 100644 vcg/complex/trimesh/refine_loop.h delete mode 100644 vcg/complex/trimesh/smooth.h delete mode 100644 vcg/complex/trimesh/stat.h delete mode 100644 vcg/complex/trimesh/subset.h diff --git a/vcg/complex/trimesh/attribute_seam.h b/vcg/complex/trimesh/attribute_seam.h deleted file mode 100644 index 1f4f3366..00000000 --- a/vcg/complex/trimesh/attribute_seam.h +++ /dev/null @@ -1,369 +0,0 @@ -#ifndef VCG_TRI_ATTRIBUTE_SEAM_H -#define VCG_TRI_ATTRIBUTE_SEAM_H - -#include - -#include - -/* - -// sample extract functor -void v_extract(const src_mesh_t & wm, const src_face_t & f, int k, const dst_mesh_t & vm, dst_vertex_t & v) -{ - (void)wm; - (void)vm; - - v.P() = f.cP (k); - v.N() = f.cWN(k); - v.C() = f.cWC(k); - v.T() = f.cWT(k); -} - -// sample compare functor -bool v_compare(const dst_mesh_t & vm, const dst_vertex_t & u, const dst_vertex_t & v) -{ - (void)vm; - - return - ( - (u.cN() == v.cN()) - && (u.cC() == v.cC()) - && (u.cT() == v.cT()) - ); -} - -// sample copy functor -void v_copy(const dst_mesh_t & vm, const dst_vertex_t & u, dst_vertex_t & v) -{ - (void)vm; - - v.P() = u.cP(); - v.N() = u.cN(); - v.C() = u.cC(); - v.T() = u.cT(); -} - -// create seams -AttributeSeam::SplitVertex(src, dst, v_extract, v_compare, v_copy, 1.10f); - -*/ - -namespace vcg -{ - -namespace tri -{ - -class AttributeSeam -{ - public: - - typedef AttributeSeam ThisType; - - enum ASMask - { - POSITION_PER_VERTEX = (1 << 0), - - NORMAL_PER_VERTEX = (1 << 1), - NORMAL_PER_WEDGE = (1 << 2), - NORMAL_PER_FACE = (1 << 3), - - COLOR_PER_VERTEX = (1 << 4), - COLOR_PER_WEDGE = (1 << 5), - COLOR_PER_FACE = (1 << 6), - - TEXCOORD_PER_VERTEX = (1 << 7), - TEXCOORD_PER_WEDGE = (1 << 8) - }; - - template - struct ASExtract - { - const unsigned int mask; - - ASExtract(unsigned int vmask = 0) : mask(vmask) - { - ; - } - - void operator () (const src_trimesh_t & sm, const typename src_trimesh_t::FaceType & f, int k, const dst_trimesh_t & dm, typename dst_trimesh_t::VertexType & v) const - { - (void)sm; - (void)dm; - - const unsigned int m = this->mask; - const typename src_trimesh_t::VertexType & u = *(f.cV(k)); - - if ((m & AttributeSeam::POSITION_PER_VERTEX) != 0) v.P() = f.cP (k); - - if ((m & AttributeSeam::NORMAL_PER_VERTEX) != 0) v.N() = u.cN ( ); - if ((m & AttributeSeam::NORMAL_PER_WEDGE) != 0) v.N() = f.cWN(k); - if ((m & AttributeSeam::NORMAL_PER_FACE) != 0) v.N() = f.cN ( ); - - if ((m & AttributeSeam::COLOR_PER_VERTEX) != 0) v.C() = u.cC ( ); - if ((m & AttributeSeam::COLOR_PER_WEDGE) != 0) v.C() = f.cWC(k); - if ((m & AttributeSeam::COLOR_PER_FACE) != 0) v.C() = f.cC ( ); - - if ((m & AttributeSeam::TEXCOORD_PER_VERTEX) != 0) v.T() = u.cT ( ); - if ((m & AttributeSeam::TEXCOORD_PER_WEDGE) != 0) v.T() = f.cWT(k); - } - }; - - template - struct ASCompare - { - const unsigned int mask; - - ASCompare(unsigned int vmask = 0) : mask(vmask) - { - ; - } - - bool operator () (const dst_trimesh_t & sm, const typename dst_trimesh_t::VertexType & u, const typename dst_trimesh_t::VertexType & v) const - { - (void)sm; - - const unsigned int m = this->mask; - - /* - if ((m & (AttributeSeam::POSITION_PER_VERTEX)) != 0) - { - if (u.cP() != v.cP()) return false; - } - */ - - if ((m & (AttributeSeam::NORMAL_PER_VERTEX | AttributeSeam::NORMAL_PER_WEDGE | AttributeSeam::NORMAL_PER_FACE)) != 0) - { - if (u.cN() != v.cN()) return false; - } - - if ((m & (AttributeSeam::COLOR_PER_VERTEX | AttributeSeam::COLOR_PER_WEDGE | AttributeSeam::COLOR_PER_FACE)) != 0) - { - if (u.cC() != v.cC()) return false; - } - - if ((m & (AttributeSeam::TEXCOORD_PER_VERTEX | AttributeSeam::TEXCOORD_PER_WEDGE)) != 0) - { - if (u.cT() != v.cT()) return false; - } - - return true; - } - }; - - // in-place version - template - static inline bool SplitVertex(src_trimesh_t & src, extract_wedge_attribs_t v_extract, compare_vertex_attribs_t & v_compare) - { - typedef typename src_trimesh_t::VertexType src_vertex_t; - typedef typename src_trimesh_t::VertexIterator src_vertex_i; - typedef typename src_trimesh_t::FaceType src_face_t; - typedef typename src_trimesh_t::FaceIterator src_face_i; - typedef typename src_trimesh_t::VertContainer src_vertex_container_t; - - typedef vcg::tri::Allocator src_mesh_allocator_t; - typedef typename src_mesh_allocator_t :: template PointerUpdater src_pointer_updater_t; - - if ((src.vn <= 0) || (src.fn <= 0)) - { - return true; - } - - src_pointer_updater_t pt_upd; - src_vertex_i vi = src_mesh_allocator_t::AddVertices(src, 1, pt_upd); - src_vertex_t * vtx = &(*vi); - src_vertex_t * vtxbase = &(src.vert[0]); - - const size_t vertex_count = src.vert.size(); - const size_t vertex_pool_size = vertex_count; - - std::vector vloc; - vloc.reserve(vertex_pool_size); - vloc.resize(vertex_count, -2); - - int vcount = int(src.vert.size()); - int idx = 0; - - for (src_face_i it=src.face.begin(); it!=src.face.end(); ++it) - { - src_face_t & f = (*it); - if (f.IsD()) continue; - - for (int k=0; k<3; ++k) - { - idx = (f.cV(k) - vtxbase); - v_extract(src, f, k, src, *vtx); - - if (vloc[idx] == -2) - { - vloc[idx] = -1; - src.vert[idx].ImportData(*vtx); - } - else - { - int vidx = idx; - do - { - if (v_compare(src, src.vert[vidx], *vtx)) break; - vidx = vloc[vidx]; - } while (vidx >= 0); - - if (vidx < 0) - { - vloc.push_back(vloc[idx]); - vloc[idx] = vcount; - - vi = src_mesh_allocator_t::AddVertices(src, 1, pt_upd); - pt_upd.Update(vtx); - pt_upd.Update(vtxbase); - - (*vi).ImportData(*vtx); - - idx = vcount; - vcount++; - } - else - { - idx = vidx; - } - } - - f.V(k) = &(src.vert[idx]); - } - } - - src_mesh_allocator_t::DeleteVertex(src, *vtx); - - return true; - } - - // out-of-place version - template - static inline bool SplitVertex(const src_trimesh_t & src, dst_trimesh_t & dst, extract_wedge_attribs_t & v_extract, compare_vertex_attribs_t & v_compare, copy_vertex_t & v_copy) - { - typedef typename src_trimesh_t::VertexType src_vertex_t; - typedef typename src_trimesh_t::FaceType src_face_t; - typedef typename src_trimesh_t::ConstFaceIterator src_face_ci; - - typedef typename dst_trimesh_t::VertContainer dst_vertex_container_t; - typedef typename dst_trimesh_t::VertexType dst_vertex_t; - typedef typename dst_trimesh_t::VertexIterator dst_vertex_i; - typedef typename dst_trimesh_t::FaceType dst_face_t; - typedef typename dst_trimesh_t::FaceIterator dst_face_i; - - typedef vcg::tri::Allocator dst_mesh_allocator_t; - - /* GCC gets in troubles and need some hints ("template") to parse the following line */ - typedef typename dst_mesh_allocator_t :: template PointerUpdater dst_pointer_updater_t; - - if (reinterpret_cast(&src) == reinterpret_cast(&dst)) - { - return false; - } - - dst.Clear(); - - if ((src.vn <= 0) || (src.fn <= 0)) - { - return true; - } - - const size_t vertex_count = src.vert.size(); - const size_t vertex_pool_size = vertex_count; - - const src_vertex_t * vtxbase = &(src.vert[0]); - - std::vector vloc; - vloc.reserve(vertex_pool_size); - vloc.resize(vertex_count, -2); - - dst_vertex_i vv; - dst_pointer_updater_t pt_upd; - pt_upd.preventUpdateFlag = true; - dst_mesh_allocator_t::AddVertices(dst, 1 + int(vertex_count), pt_upd); - dst_vertex_t * vtx = &(dst.vert[0]); - - dst_face_i fbase = dst_mesh_allocator_t::AddFaces(dst, src.fn); - dst_face_i fi = fbase; - - int vcount = int(dst.vert.size()); - int idx = 0; - - for (src_face_ci it=src.face.begin(); it!=src.face.end(); ++it) - { - const src_face_t & wf = (*it); - if (wf.IsD()) continue; - - dst_face_t & vf = (*fi); - - for (int k=0; k<3; ++k) - { - idx = (wf.cV(k) - vtxbase); - - v_extract(src, wf, k, dst, *vtx); - - if (vloc[idx] == -2) - { - vloc[idx] = -1; - v_copy(dst, *vtx, dst.vert[idx]); - } - else - { - int vidx = idx; - do - { - if (v_compare(dst, dst.vert[vidx], *vtx)) break; - vidx = vloc[vidx]; - } while (vidx >= 0); - - if (vidx < 0) - { - vloc.push_back(vloc[idx]); - vloc[idx] = vcount; - - vv = dst_mesh_allocator_t::AddVertices(dst, 1, pt_upd); - pt_upd.Update(vtx); - v_copy(dst, *vtx, *vv); - - idx = vcount; - vcount++; - } - else - { - idx = vidx; - } - } - - vf.V(k) = reinterpret_cast(idx); - } - - fi++; - } - - { - std::vector tmp; - vloc.swap(tmp); - } - - dst_vertex_t * vstart = &(dst.vert[0]); - - for (dst_face_i it=fbase; it!=dst.face.end(); ++it) - { - dst_face_t & vf = (*it); - - vf.V(0) = vstart + reinterpret_cast(vf.V(0)); - vf.V(1) = vstart + reinterpret_cast(vf.V(1)); - vf.V(2) = vstart + reinterpret_cast(vf.V(2)); - } - - dst_mesh_allocator_t::DeleteVertex(dst, *vtx); - - return true; - } -}; - -} // end namespace tri - -} // end namespace vcg - -#endif // VCG_TRI_ATTRIBUTE_SEAM_H diff --git a/vcg/complex/trimesh/autoalign_4pcs.h b/vcg/complex/trimesh/autoalign_4pcs.h deleted file mode 100644 index fac74aec..00000000 --- a/vcg/complex/trimesh/autoalign_4pcs.h +++ /dev/null @@ -1,677 +0,0 @@ -#ifndef _4PCS_ -#define _4PCS_ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ -/** -implementation of the 4PCS method from the paper: -"4-Points Congruent Sets for Robust Pairwise Surface Registration" -D.Aiger, N.Mitra D.Cohen-Or, SIGGRAPH 2008 -ps: the name of the variables are out of vcg standard but like the one -used in the paper pseudocode. -*/ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - - - -// note: temporary (callback.h should be moved inside vcg) -typedef bool AACb( const int pos,const char * str ); - -namespace vcg{ - namespace tri{ -template -class FourPCS { -public: - /* mesh only for using spatial indexing functions (to remove) */ - class PVertex; // dummy prototype never used - class PFace; - - class PUsedTypes: public vcg::UsedTypes < vcg::Use::template AsVertexType, - vcg::Use::template AsFaceType >{}; - - - class PVertex : public vcg::Vertex< PUsedTypes,vcg::vertex::BitFlags,vcg::vertex::Coord3f ,vcg::vertex::Mark>{}; - /*same as for the vertes */ - class PFace : public vcg::Face< PUsedTypes> {}; - /*the mesh is a container of vertices and a container of faces */ - class PMesh : public vcg::tri::TriMesh< std::vector, std::vector > {}; - - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::VertexType VertexType; - typedef vcg::Point4< vcg::Point3 > FourPoints; - typedef vcg::GridStaticPtr GridType; - - /* class for Parameters */ - struct Parameters{ - ScalarType delta; - int feetsize; // how many points in the neighborhood of each of the 4 points - ScalarType f; // overlapping estimation - int scoreFeet, // how many of the feetsize points must match (max feetsize*4) to try an early interrupt - scoreAln; // how good must be the alignement to end the process successfully - - void Default(){ - delta = 0.5; - feetsize = 25; - f = 0.5; - scoreFeet = 50; - scoreAln = 200; - } - }; - - Parameters prs; /// parameters - - public: - void Init(MeshType &_P,MeshType &_Q); - bool Align( int L, vcg::Matrix44f & result, AACb * cb = NULL ); // main function - - -private: - struct Couple: public std::pair{ - Couple(const int & i, const int & j, float d):std::pair(i,j),dist(d){} - Couple(float d):std::pair(0,0),dist(d){} - float dist; - const bool operator < (const Couple & o) const {return dist < o.dist;} - int & operator[](const int &i){return (i==0)? first : second;} - }; - - - - - /* returns the closest point between to segments x1-x2 and x3-x4. */ - void IntersectionLineLine(const CoordType & x1,const CoordType & x2,const CoordType & x3,const CoordType & x4, CoordType&x) - { - CoordType a = x2-x1, b = x4-x3, c = x3-x1; - x = x1 + a * ((c^b).dot(a^b)) / (a^b).SquaredNorm(); - } - - - - - struct CandiType{ - CandiType(){}; - CandiType(FourPoints _p,vcg::Matrix44_T):p(_p),T(_T){} - FourPoints p; - vcg::Matrix44 T; - ScalarType err; - int score; - int base; // debug: for which base - inline bool operator <(const CandiType & o) const {return score > o.score;} - }; - - - MeshType *P, // mesh from which the coplanar base is selected - *Q; // mesh where to find the correspondences - std::vector mapsub; // subset of index to the vertices in Q - - - PMesh Invr; // invariants - - std::vector< CandiType > U; - CandiType winner; - int iwinner; // winner == U[iwinner] - - FourPoints B; // coplanar base - std::vector bases; // used bases - ScalarType side; // side - std::vector ExtB[4]; // selection of vertices "close" to the four point - std::vector subsetP; // random selection on P - ScalarType radius; - - ScalarType Bangle; - std::vector R1/*,R2*/; - ScalarType r1,r2; - - // class for the point 'ei' - struct EPoint{ - EPoint(vcg::Point3 _p, int _i):pos(_p),pi(_i){} - vcg::Point3 pos; - int pi; //index to R[1|2] - void GetBBox(vcg::Box3 & b){b.Add(pos);} - }; - - GridType *ugrid; // griglia - vcg::GridStaticPtr ugridQ; - vcg::GridStaticPtr ugridP; - - //FILE * f; - -//private: - bool SelectCoplanarBase(); // on P - bool FindCongruent() ; // of base B, on Q, with approximation delta - -//private: - void ComputeR1R2(ScalarType d1,ScalarType d2); - - bool IsTransfCongruent(FourPoints fp,vcg::Matrix44 & mat, float & trerr); - int EvaluateSample(CandiType & fp, CoordType & tp, CoordType & np, const float & angle); - void EvaluateAlignment(CandiType & fp); - void TestAlignment(CandiType & fp); - - /* debug tools */ -public: - std::vector allTr;// tutte le trasformazioni provate - FILE * db; - char namemesh1[255],namemesh2[255]; - int n_base; - void InitDebug(const char * name1, const char * name2){ - db = fopen("debugPCS.txt","w"); - sprintf(&namemesh1[0],"%s",name1); - sprintf(&namemesh2[0],"%s",name2); - n_base = 0; - } - - void FinishDebug(){ - fclose(db); - } - //void SaveALN(char * name,vcg::Matrix44f mat ){ - // FILE * o = fopen(name,"w"); - // fprintf(o,"2\n%s\n#\n",namemesh1); - // for(int i = 0 ; i < 4; ++i) - // fprintf(o,"%f %f %f %f\n",mat[i][0],mat[i][1],mat[i][2],mat[i][3]); - // fprintf(o,"%s\n#\n",namemesh2); - // fprintf(o,"1.0 0.0 0.0 0.0 \n"); - // fprintf(o,"0.0 1.0 0.0 0.0 \n"); - // fprintf(o,"0.0 0.0 1.0 0.0 \n"); - // fprintf(o,"0.0 0.0 0.0 1.0 \n"); - - // fclose(o); - //} - -}; - -template -void -FourPCS:: Init(MeshType &_P,MeshType &_Q){ - - P = &_P;Q=&_Q; - ugridQ.Set(Q->vert.begin(),Q->vert.end()); - ugridP.Set(P->vert.begin(),P->vert.end()); - int vi; - // float areaP = vcg::tri::Stat::ComputeMeshArea(*P); - // float areaQ = vcg::tri::Stat::ComputeMeshArea(*Q); - - float ratio = 800 / (float) Q->vert.size(); - for(vi = 0; vi < Q->vert.size(); ++vi) - if(rand()/(float) RAND_MAX < ratio) - mapsub.push_back(vi); - - for(vi = 0; vi < P->vert.size(); ++vi) - if(rand()/(float) RAND_MAX < ratio) - subsetP.push_back(&P->vert[vi]); - - // estimate neigh distance - float avD = 0.0,dist; - for(int i = 0 ; i < 100; ++i){ - int ri = rand()/(float) RAND_MAX * Q->vert.size() -1; - std::vector< CoordType > samples,d_samples; - std::vector dists; - std::vector ress; - vcg::tri::GetKClosestVertex< - MeshType, - vcg::GridStaticPtr, - std::vector, - std::vector, - std::vector< CoordType > >(*Q,ugridQ,2,Q->vert[ri].cP(),Q->bbox.Diag(), ress,dists, samples); - assert(ress.size() == 2); - avD+=dists[1]; - } - avD /=100; // average vertex-vertex distance - avD /= sqrt(ratio); // take into account the ratio - - prs.delta = avD * prs.delta; - side = P->bbox.Dim()[P->bbox.MaxDim()]*prs.f; //rough implementation - - } - -template -bool -FourPCS::SelectCoplanarBase(){ - - vcg::tri::UpdateBounding::Box(*P); - - // choose the inter point distance - ScalarType dtol = side*0.1; //rough implementation - - //choose the first two points - int i = 0,ch; - - // first point random - ch = (rand()/(float)RAND_MAX)*(P->vert.size()-2); - B[0] = P->vert[ch].P(); -//printf("B[0] %d\n",ch); - // second a point at distance d+-dtol - for(i = 0; i < P->vert.size(); ++i){ - ScalarType dd = (P->vert[i].P() - B[0]).Norm(); - if( ( dd < side + dtol) && (dd > side - dtol)){ - B[1] = P->vert[i].P(); -//printf("B[1] %d\n",i); - break; - } - } - if(i == P->vert.size()) - return false; - - // third point at distance d from B[1] and forming a right angle - int best = -1; ScalarType bestv=std::numeric_limits::max(); - for(i = 0; i < P->vert.size(); ++i){ - int id = rand()/(float)RAND_MAX * (P->vert.size()-1); - ScalarType dd = (P->vert[id].P() - B[1]).Norm(); - if( ( dd < side + dtol) && (dd > side - dtol)){ - ScalarType angle = fabs( ( P->vert[id].P()-B[1]).normalized().dot((B[1]-B[0]).normalized())); - if( angle < bestv){ - bestv = angle; - best = id; - } - } - } - if(best == -1) - return false; - B[2] = P->vert[best].P(); -//printf("B[2] %d\n",best); - - CoordType n = ((B[0]-B[1]).normalized() ^ (B[2]-B[1]).normalized()).normalized(); - CoordType B4 = B[1] + (B[0]-B[1]) + (B[2]-B[1]); - VertexType * v =0; - ScalarType radius = dtol*4.0; - - std::vector closests; - std::vector distances; - std::vector points; - - vcg::tri::GetInSphereVertex< - MeshType, - vcg::GridStaticPtr, - std::vector, - std::vector, - std::vector - >(*P,ugridP,B4,radius,closests,distances,points); - - if(closests.empty()) - return false; - best = -1; bestv=std::numeric_limits::max(); - for(i = 0; i P() - B[1]).normalized().dot(n)); - if( angle < bestv){ - bestv = angle; - best = i; - } - } - B[3] = closests[best]->P(); - -//printf("B[3] %d\n", (typename MeshType::VertexType*)closests[best] - &(*P->vert.begin())); - - // compute r1 and r2 - CoordType x; - std::swap(B[1],B[2]); - IntersectionLineLine(B[0],B[1],B[2],B[3],x); - - r1 = (x - B[0]).dot(B[1]-B[0]) / (B[1]-B[0]).SquaredNorm(); - r2 = (x - B[2]).dot(B[3]-B[2]) / (B[3]-B[2]).SquaredNorm(); - - if( ((B[0]+(B[1]-B[0])*r1)-(B[2]+(B[3]-B[2])*r2)).Norm() > prs.delta ) - return false; - - radius =side*0.5; - std::vector< CoordType > samples,d_samples; - std::vector dists; - - for(int i = 0 ; i< 4; ++i){ - vcg::tri::GetKClosestVertex< - MeshType, - vcg::GridStaticPtr, - std::vector, - std::vector, - std::vector< CoordType > >(*P,ugridP, prs.feetsize ,B[i],radius, ExtB[i],dists, samples); - } - - //for(int i = 0 ; i< 4; ++i) - // printf("%d ",ExtB[i].size()); - // printf("\n"); -return true; - -} - - -template -bool -FourPCS::IsTransfCongruent(FourPoints fp,vcg::Matrix44 & mat, float & trerr){ - - std::vector > fix; - std::vector > mov; - for(int i = 0 ; i < 4; ++i) mov.push_back(B[i]); - for(int i = 0 ; i < 4; ++i) fix.push_back(fp[i]); - - vcg::Point3 n,p; - n = (( B[1]-B[0]).normalized() ^ ( B[2]- B[0]).normalized())*( B[1]- B[0]).Norm(); - p = B[0] + n; - mov.push_back(p); - n = (( fp[1]-fp[0]).normalized() ^ (fp[2]- fp[0]).normalized())*( fp[1]- fp[0]).Norm(); - p = fp[0] + n; - fix.push_back(p); - - vcg::PointMatching::ComputeRigidMatchMatrix(mat,fix,mov); - - ScalarType err = 0.0; - for(int i = 0; i < 4; ++i) err+= (mat * mov[i] - fix[i]).SquaredNorm(); - - trerr = vcg::math::Sqrt(err); - return err < prs.delta* prs.delta*4.0; - } - -template -void -FourPCS::ComputeR1R2(ScalarType d1,ScalarType d2){ - int vi,vj; - R1.clear(); - //R2.clear(); - int start = clock(); - for(vi = 0; vi < mapsub.size(); ++vi) for(vj = vi; vj < mapsub.size(); ++vj){ - ScalarType d = ((Q->vert[mapsub[vi]]).P()-(Q->vert[mapsub[vj]]).P()).Norm(); - if( (d < d1+ side*0.5) && (d > d1-side*0.5)) - { - R1.push_back(Couple(mapsub[vi],mapsub[vj],d )); - R1.push_back(Couple(mapsub[vj],mapsub[vi],d)); - } - } - //for( vi = 0; vi < mapsub.size(); ++ vi ) for( vj = vi ; vj < mapsub.size(); ++ vj ){ - // ScalarType d = ((Q->vert[mapsub[vi]]).P()-(Q->vert[mapsub[vj]]).P()).Norm(); - // if( (d < d2+side*0.5) && (d > d2-side*0.5)) - // { - // R2.push_back(Couple(mapsub[vi],mapsub[vj],d)); - // R2.push_back(Couple(mapsub[vj],mapsub[vi],d)); - // } - //} - - std::sort(R1.begin(),R1.end()); -// std::sort(R2.begin(),R2.end()); -} - -template -bool -FourPCS::FindCongruent() { // of base B, on Q, with approximation delta - bool done = false; - std::vector R2inv; - int n_closests = 0, n_congr = 0; - int ac =0 ,acf = 0,tr = 0,trf =0; - ScalarType d1,d2; - d1 = (B[1]-B[0]).Norm(); - d2 = (B[3]-B[2]).Norm(); - - int start = clock(); - //int vi,vj; - - typename PMesh::VertexIterator vii; - typename std::vector::iterator bR1,eR1,bR2,eR2,ite,cite; - bR1 = std::lower_bound::iterator,Couple>(R1.begin(),R1.end(),Couple(d1-prs.delta*2.0)); - eR1 = std::lower_bound::iterator,Couple>(R1.begin(),R1.end(),Couple(d1+prs.delta*2.0)); - bR2 = std::lower_bound::iterator,Couple>(R1.begin(),R1.end(),Couple(d2-prs.delta*2.0)); - eR2 = std::lower_bound::iterator,Couple>(R1.begin(),R1.end(),Couple(d2+prs.delta*2.0)); - - // in [bR1,eR1) there are all the pairs ad a distance d1 +- prs.delta - // in [bR1,eR1) there are all the pairs ad a distance d2 +- prs.delta - - if(bR1 == R1.end()) return false;// if there are no such pairs return - if(bR2 == R1.end()) return false; // if there are no such pairs return - - // put [bR1,eR1) in a mesh to have the search operator for free (lazy me) - Invr.Clear(); - int i = &(*bR1)-&(*R1.begin()); - for(ite = bR1; ite != eR1;++ite){ - vii = vcg::tri::Allocator::AddVertices(Invr,1); - (*vii).P() = Q->vert[R1[i][0]].P() + (Q->vert[R1[i][1]].P()-Q->vert[R1[i][0]].P()) * r1; - ++i; - } - if(Invr.vert.empty() ) return false; - - // index remaps a vertex of Invr to its corresponding point in R1 - typename PMesh::template PerVertexAttributeHandle id = vcg::tri::Allocator::template AddPerVertexAttribute(Invr,std::string("index")); - i = &(*bR1)-&(*R1.begin()); - for(vii = Invr.vert.begin(); vii != Invr.vert.end();++vii,++i) id[vii] = i; - - vcg::tri::UpdateBounding::Box(Invr); - // printf("Invr size %d\n",Invr.vn); - - ugrid = new GridType(); - ugrid->Set(Invr.vert.begin(),Invr.vert.end()); - - i = &(*bR2)-&(*R1.begin()); - // R2inv contains all the points generated by the couples in R2 (with the reference to remap into R2) - for(ite = bR2; ite != eR2;++ite){ - R2inv.push_back( EPoint( Q->vert[R1[i][0]].P() + (Q->vert[R1[i][1]].P()-Q->vert[R1[i][0]].P()) * r2,i)); - ++i; - } - - n_closests = 0; n_congr = 0; ac =0 ; acf = 0; tr = 0; trf = 0; - // fprintf(db,"R2Inv.size = %d \n",R2inv.size()); - for(uint i = 0 ; i < R2inv.size() ; ++i){ - - std::vector closests; - std::vector distances; - std::vector points; - - // for each point in R2inv get all the points in R1 closer than prs.delta - vcg::Matrix44 mat; - vcg::Box3f bb; - bb.Add(R2inv[i].pos+vcg::Point3f(prs.delta * 0.1,prs.delta * 0.1 , prs.delta * 0.1 )); - bb.Add(R2inv[i].pos-vcg::Point3f(prs.delta * 0.1,prs.delta* 0.1 , prs.delta* 0.1)); - - vcg::tri::GetInBoxVertex > - (Invr,*ugrid,bb,closests); - - n_closests+=closests.size(); - for(uint ip = 0; ip < closests.size(); ++ip){ - FourPoints p; - p[0] = Q->vert[R1[id[closests[ip]]][0]].P(); - p[1] = Q->vert[R1[id[closests[ip]]][1]].P(); - p[2] = Q->vert[R1[ R2inv[i].pi][0]].P(); - p[3] = Q->vert[R1[ R2inv[i].pi][1]].P(); - - float trerr; - n_base++; - if(!IsTransfCongruent(p,mat,trerr)) { - trf++; - //char name[255]; - //sprintf(name,"faileTR_%d_%f.aln",n_base,trerr); - //fprintf(db,"TransCongruent %s\n", name); - //SaveALN(name, mat); - } - else{ - tr++; - n_congr++; - U.push_back(CandiType(p,mat)); - EvaluateAlignment(U.back()); - U.back().base = bases.size()-1; - - if( U.back().score > prs.scoreFeet){ - TestAlignment(U.back()); - if(U.back().score > prs.scoreAln) - { - done = true; break; - } - } - //char name[255]; - //sprintf(name,"passed_score_%5d_%d.aln",U.back().score,n_base); - //fprintf(db,"OK TransCongruent %s, score: %d \n", name,U.back().score); - //SaveALN(name, mat); - } - } - } - - delete ugrid; - vcg::tri::Allocator::DeletePerVertexAttribute(Invr,id); - printf("n_closests %5d = (An %5d ) + ( Tr %5d ) + (OK) %5d\n",n_closests,acf,trf,n_congr); - - return done; -// printf("done n_closests %d congr %d in %f s\n ",n_closests,n_congr,(clock()-start)/(float)CLOCKS_PER_SEC); -// printf("angle:%d %d, trasf %d %d\n",ac,acf,tr,trf); -} - - - -template -int FourPCS::EvaluateSample(CandiType & fp, CoordType & tp, CoordType & np, const float & angle){ - VertexType* v; - ScalarType dist ; - radius = prs.delta; - tp = fp.T * tp; - - vcg::Point4 np4; - np4 = fp.T * vcg::Point4(np[0],np[1],np[2],0.0); - np[0] = np4[0]; np[1] = np4[1]; np[2] = np4[2]; - - v = 0; - //v = vcg::tri::GetClosestVertex< - // MeshType, - // vcg::GridStaticPtr - // >(*Q,ugridQ,tp,radius, dist ); - typename MeshType::VertexType vq; - vq.P() = tp; - vq.N() = np; - v = vcg::tri::GetClosestVertexNormal< - MeshType, - vcg::GridStaticPtr - >(*Q,ugridQ,vq,radius, dist ); - - if(v!=0) - if( v->N().dot(np) -angle >0) return 1; else return -1; - -} - - -template -void -FourPCS::EvaluateAlignment(CandiType & fp){ - int n_delta_close = 0; - for(int i = 0 ; i< 4; ++i) { - for(uint j = 0; j < ExtB[i].size();++j){ - CoordType np = ExtB[i][j]->cN();; - CoordType tp = ExtB[i][j]->P(); - n_delta_close+=EvaluateSample(fp,tp,np,0.9); - } - } - fp.score = n_delta_close; -} - -template -void -FourPCS::TestAlignment(CandiType & fp){ - radius = prs.delta; - int n_delta_close = 0; - for(uint j = 0; j < subsetP.size();++j){ - CoordType np = subsetP[j]->N(); - CoordType tp = subsetP[j]->P(); - n_delta_close+=EvaluateSample(fp,tp,np,0.6); - } - fp.score = n_delta_close; -} - - -template -bool -FourPCS:: Align( int L, vcg::Matrix44f & result, AACb * cb ){ // main loop - - int bestv = 0; - bool found; - int n_tries = 0; - U.clear(); - - if(L==0) - { - L = (log(1.0-0.9999) / log(1.0-pow((float)prs.f,3.f)))+1; - printf("using %d bases\n",L); - } - - ComputeR1R2(side*1.4,side*1.4); - - for(int t = 0; t < L; ++t ){ - do{ - n_tries = 0; - do{ - n_tries++; - found = SelectCoplanarBase(); - } - while(!found && (n_tries <50)); - if(!found) { - prs.f*=0.98; - side = P->bbox.Dim()[P->bbox.MaxDim()]*prs.f; //rough implementation - ComputeR1R2(side*1.4,side*1.4); - } - } while (!found && (prs.f >0.1)); - - if(prs.f <0.1) { - printf("FAILED"); - return false; - } - bases.push_back(B); - if(cb) cb(t*100/L,"trying bases"); - if(FindCongruent()) - break; - } - - if(U.empty()) return false; - - std::sort(U.begin(),U.end()); - - bestv = -std::numeric_limits::max(); - iwinner = 0; - - for(int i = 0 ; i < U.size() ;++i) - { - TestAlignment(U[i]); - if(U[i].score > bestv){ - bestv = U[i].score; - iwinner = i; - } - } - - printf("Best score: %d \n", bestv); - - winner = U[iwinner]; - result = winner.T; - - // deallocations - Invr.Clear(); - - return true; -} - - } // namespace tri -} // namespace vcg -#endif diff --git a/vcg/complex/trimesh/bitquad_creation.h b/vcg/complex/trimesh/bitquad_creation.h deleted file mode 100644 index af25fd00..00000000 --- a/vcg/complex/trimesh/bitquad_creation.h +++ /dev/null @@ -1,788 +0,0 @@ -#include -#include - -/** BIT-QUAD creation support: - a collection of methods that, - starting from a triangular mesh, will create your quad-pure or quad-domainant mesh. - - They all require: - - per face Q, and FF connectivity, 2-manyfold meshes, - - and tri- or quad- meshes (no penta, etc) (if in need, use MakeBitTriOnly) - - -[ list of available methods: ] - -void MakePureByRefine(Mesh &m) - - adds a vertex for each tri or quad present - - thus, miminal complexity increase is the mesh is quad-dominant already - - old non-border edges are made faux - - never fails - -void MakePureByCatmullClark(MeshType &m) - - adds a vertex in each (non-faux) edge. - - twice complexity increase w.r.t. "ByRefine" method. - - preserves edges: old edges are still edges - - never fails - -bool MakePureByFlip(MeshType &m [, int maxdist] ) - - does not increase # vertices, just flips edges - - call in a loop until it returns true (temporary hack) - - fails if number of triangle is odd (only happens in open meshes) - - add "StepByStep" to method name if you want it to make a single step (debugging purposes) - -bool MakeTriEvenBySplit(MeshType& m) -bool MakeTriEvenByDelete(MeshType& m) - - two simple variants that either delete or split *at most one* border face - so that the number of tris will be made even. Return true if it did it. - - useful to use the previous method, when mesh is still all triangle - -void MakeDominant(MeshType &m, int level) - - just merges traingle pairs into quads, trying its best - - various heuristic available, see descr. for parameter "level" - - provides good starting point for make-Quad-Only methods - - uses an ad-hoc measure for "quad quality" (which is hard-wired, for now) - -void MakeBitTriOnly(MeshType &m) - - inverse process: returns to tri-only mesh - - -(more info in comments before each method) - -*/ -#ifndef VCG_BITQUAD_CRE -#define VCG_BITQUAD_CRE - -namespace vcg{namespace tri{ - -template > -class BitQuadCreation{ - -public: - -typedef _MeshType MeshType; -typedef typename MeshType::ScalarType ScalarType; -typedef typename MeshType::CoordType CoordType; -typedef typename MeshType::FaceType FaceType; -typedef typename MeshType::FaceType* FaceTypeP; -typedef typename MeshType::VertexType VertexType; -typedef typename MeshType::FaceIterator FaceIterator; -typedef typename MeshType::VertexIterator VertexIterator; - -typedef BitQuad BQ; // static class to make basic quad operations - - -// helper function: -// given a triangle, merge it with its best neightboord to form a quad -template -static void selectBestDiag(FaceType *fi){ - - if (!override) { - if (fi->IsAnyF()) return; - } - - // select which edge to make faux (if any)... - int whichEdge = -1; - ScalarType bestScore = fi->Q(); - - whichEdge=-1; - - for (int k=0; k<3; k++){ - - // todo: check creases? (continue if edge k is a crease) - - if (!override) { - if (fi->FFp(k)->IsAnyF()) continue; - } - if (fi->FFp(k)==fi) continue; // never make a border faux - - ScalarType score = BQ::quadQuality( &*fi, k ); - if (override) { - // don't override anyway iff other face has a better match - if (score < fi->FFp(k)->Q()) continue; - } - if (score>bestScore) { - bestScore = score; - whichEdge = k; - } - } - - // ...and make it faux - if (whichEdge>=0) { - //if (override && fi->FFp(whichEdge)->IsAnyF()) { - // new score is the average of both scores - // fi->Q() = fi->FFp(whichEdge)->Q() = ( bestScore + fi->FFp(whichEdge)->Q() ) /2; - //} else { - //} - - if (override) { - // clear any faux edge of the other face - for (int k=0; k<3; k++) - if (fi->FFp(whichEdge)->IsF(k)) { - fi->FFp(whichEdge)->ClearF(k); - fi->FFp(whichEdge)->FFp(k)->ClearF( fi->FFp(whichEdge)->FFi(k) ); - fi->FFp(whichEdge)->FFp(k)->Q()=0.0; // other face's ex-buddy is now single and sad :( - } - - // clear all faux edges of this face... - for (int k=0; k<3; k++) - if (fi->IsF(k)) { - fi->ClearF(k); - fi->FFp(k)->ClearF( fi->FFi(k) ); - fi->FFp(k)->Q()= 0.0; // my ex-buddy is now sad - } - } - // set (new?) quad - fi->SetF(whichEdge); - fi->FFp(whichEdge)->SetF( fi->FFi(whichEdge) ); - fi->Q() = fi->FFp(whichEdge)->Q() = bestScore; - - } - - -} - - - -// helper funcion: -// a pass though all triangles to merge triangle pairs into quads -template // override previous decisions? -static void MakeDominantPass(MeshType &m){ - - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - selectBestDiag(&(*fi)); - } - -} -/** - * This function split a face along the specified border edge it does not compute any property of the new vertex. It only do the topological work. - * @param edge Index of the edge - */ -// sideF -// sideF V2(e) ------------- v2 -// V0 -------------V2 V2(e) \ / -// | / | \ \ newF / -// | / | \ \ / e -// | f / | \ \ / -// | / e | f V1(e)=newV = -// | / | / -// | / | / -// | / | / -// V1 V0(e) -// - -static std::pair FaceSplitBorderEdge(MeshType &m, typename MeshType::FaceType &f, int edge, typename MeshType::FaceType *newFace, typename MeshType::VertexType *newVert ) -{ - - typename MeshType::FaceType *sideFFp; - int sideFFi; - - assert(tri::HasFFAdjacency(m)); - assert(face::IsBorder(f,edge)); - //qDebug("OldFacePRE %i %i %i",tri::Index(m,f.V(0)),tri::Index(m,f.V(1)),tri::Index(m,f.V(2))); - if(newFace==0) newFace=&*tri::Allocator::AddFaces(m,1); - if(newVert==0) { - newVert=&*tri::Allocator::AddVertices(m,1); - newVert->P()=(f.P0(edge)+f.P1(edge))/2.0; - } - newFace->V0(edge)=newVert; - newFace->V1(edge)=f.V1(edge); - newFace->V2(edge)=f.V2(edge); - - f.V1(edge)=newVert; - - //qDebug("NewFace %i %i %i",tri::Index(m,newFace->V(0)),tri::Index(m,newFace->V(1)),tri::Index(m,newFace->V(2))); - //qDebug("OldFace %i %i %i",tri::Index(m,f.V(0)),tri::Index(m,f.V(1)),tri::Index(m,f.V(2))); - - // Topology - - newFace->FFp((edge+2)%3) = &f; - newFace->FFi((edge+2)%3) = (edge+1)%3; - - newFace->FFp((edge+0)%3) = newFace; - newFace->FFi((edge+0)%3) = (edge+0)%3; - - newFace->FFp((edge+1)%3) = f.FFp((edge+1)%3); - newFace->FFi((edge+1)%3) = f.FFi((edge+1)%3); - - sideFFp = f.FFp((edge+1)%3); - sideFFi = f.FFi((edge+1)%3); - - f.FFp((edge+1)%3) = newFace; - f.FFi((edge+1)%3) = (edge+2)%3; - - sideFFp->FFp(sideFFi)=newFace; - sideFFp->FFi(sideFFi)=(edge+1)%3; - - assert(face::IsBorder(f,edge)); - assert(face::IsBorder(*newFace,edge)); - - return std::make_pair(newFace,newVert); -} -// make tri count even by splitting a single triangle... -// -// V0 -------V2 V0 --------V2 -// | / | \ Fnew / -// | / | Vnew -// | / | / -// | / | / -// V1 V1 -// - -static bool MakeTriEvenBySplit(MeshType& m){ - if (m.fn%2==0) return false; // it's already Even - // Search for a triangle on the border - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) - { - if(!(*fi).IsD()) - { - for (int k=0; k<3; k++) { - if (face::IsBorder(*fi,k)){ - // We have found a face with a border - int index=tri::Index(m,*fi); - VertexIterator vnew=tri::Allocator::AddVertices(m,1); - (*vnew).P()=((*fi).P0(k)+(*fi).P1(k))/2.0; - - FaceIterator fnew=tri::Allocator::AddFaces(m,1); - - FaceSplitBorderEdge(m,m.face[index],k,&*fnew,&*vnew); - return true; - } - } - } - - } - return true; -} - -// make tri count even by delete... -static bool MakeTriEvenByDelete(MeshType& m) -{ - if (m.fn%2==0) return false; // it's already Even - - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) { - for (int k=0; k<3; k++) { - if (face::IsBorder(*fi,k) ) { - FFDetachManifold(*fi,(k+1)%3); - FFDetachManifold(*fi,(k+2)%3); - Allocator::DeleteFace(m,*fi); - return true; - } - } - } - assert(0); // no border face found? then how could the number of tri be Odd? - return true; -} - - -/** - Given a mesh, makes it bit trianglular (makes all edges NOT faux) -*/ -static void MakeBitTriOnly(MeshType &m){ - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) { - fi->ClearAllF(); - } -} - -/** given a quad-and-tree mesh, enforces the "faux edge is 2nd edge" convention. - * Requires (and updates): FV and FF structure - * Updates: faux flags - * Updates: per wedge attributes, if any - * Other connectivity structures, and per edge and per wedge flags are ignored - */ -static bool MakeBitTriQuadConventional(MeshType &m){ - assert(0); // todo -} - -/* returns true if mesh is a "conventional" quad mesh. - I.e. if it is all quads, with third edge faux fora all triangles*/ -static bool IsBitTriQuadConventional(MeshType &m){ - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - if (fi->IsAnyF()) - if ( (fi->Flags() & FaceType::FAUX012 ) != FaceType::FAUX2 ) { - return false; - } - } - return true; -} -static void CopyTopology(FaceType *fnew, FaceType * fold) -{ - fnew->FFp(0)=fold->FFp(0); fnew->FFi(0)=fold->FFi(0); - fnew->FFp(1)=fold->FFp(1); fnew->FFi(1)=fold->FFi(1); - fnew->FFp(2)=fold->FFp(2); fnew->FFi(2)=fold->FFi(2); - fnew->V(0) = fold->V(0); - fnew->V(1) = fold->V(1); - fnew->V(2) = fold->V(2); -} -/** - makes any mesh quad only by refining it so that a quad is created over all - previous diags - requires that the mesh is made only of quads and tris. -*/ -static void MakePureByRefine(MeshType &m){ - - // todo: update VF connectivity if present - - - int ev = 0; // EXTRA vertices (times 2) - int ef = 0; // EXTRA faces - - // first pass: count triangles to be added - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - int k=0; - if (face::IsBorder(*fi,0)) k++; - if (face::IsBorder(*fi,1)) k++; - if (face::IsBorder(*fi,2)) k++; - if (!fi->IsAnyF()) { - // it's a triangle - if (k==0) // add a vertex in the center of the face, splitting it in 3 - { ev+=2; ef+=2; } - if (k==1) // add a vertex in the border edge, splitting it in 2 - { } - if (k==2) // do nothing, just mark the non border edge as faux - { } - if (k==3) // disconnected single triangle (all borders): make one edge as faus - { } - } - else { - // assuming is a quad (not a penta, etc), i.e. only one faux - // add a vertex in the center of the faux edge, splitting the face in 2 - ev+=1; ef+=1; - assert(k!=3); - } - } - assert(ev%2==0); // should be even by now - ev/=2; // I was counting each of them twice - - //int originalFaceNum = m.fn; - FaceIterator nfi = tri::Allocator::AddFaces(m,ef); - VertexIterator nvi = tri::Allocator::AddVertices(m,ev); - - tri::UpdateFlags::FaceClearV(m); - - // second pass: add faces and vertices - int nsplit=0; // spits to be done on border in the third pass - for (FaceIterator fi = m.face.begin(), fend = nfi; fi!=fend; fi++) if (!fi->IsD() && !fi->IsV() ) { - - fi->SetV(); - - if (!fi->IsAnyF()) { - // it's a triangle - - int k=0; // number of borders - if (face::IsBorder(*fi,0)) k++; - if (face::IsBorder(*fi,1)) k++; - if (face::IsBorder(*fi,2)) k++; - - if (k==0) // add a vertex in the center of the face, splitting it in 3 - { - assert(nvi!=m.vert.end()); - VertexType *nv = &*nvi; nvi++; - //*nv = *fi->V0( 0 ); // lazy: copy everything from the old vertex - nv->ImportData(*(fi->V0( 0 ))); // lazy: copy everything from the old vertex - - nv->P() = ( fi->V(0)->P() + fi->V(1)->P() + fi->V(2)->P() ) /3.0; - FaceType *fa = &*fi; - FaceType *fb = &*nfi; nfi++; - FaceType *fc = &*nfi; nfi++; - - fb->ImportData(*fa); CopyTopology(fb,fa); - fc->ImportData(*fa); CopyTopology(fc,fa); - - fa->V(0) = nv; - fb->V(1) = nv; - fc->V(2) = nv; - - fb->FFp(2)=fa->FFp(2); fb->FFi(2)=fa->FFi(2); - fc->FFp(0)=fa->FFp(0); fc->FFi(0)=fa->FFi(0); - - assert( fa->FFp(1)->FFp(fa->FFi(1)) == fa ); - /* */fb->FFp(2)->FFp(fb->FFi(2)) = fb; - /* */fc->FFp(0)->FFp(fc->FFi(0)) = fc; - - fa->FFp(0) = fc; fa->FFp(2) = fb; fa->FFi(0) = fa->FFi(2) = 1; - fb->FFp(1) = fa; fb->FFp(0) = fc; fb->FFi(0) = fb->FFi(1) = 2; - fc->FFp(1) = fa; fc->FFp(2) = fb; fc->FFi(1) = fc->FFi(2) = 0; - - if (fb->FFp(2)==fa) fb->FFp(2)=fb; // recover border status - if (fc->FFp(0)==fa) fc->FFp(0)=fc; - - fa->ClearAllF(); - fb->ClearAllF(); - fc->ClearAllF(); - fa->SetF(1); - fb->SetF(2); - fc->SetF(0); - - fa->SetV();fb->SetV();fc->SetV(); - } - if (k==1) { // make a border face faux, anf other two as well - fi->SetF(0); - fi->SetF(1); - fi->SetF(2); - nsplit++; - } - if (k==2) // do nothing, just mark the non border edge as faux - { - fi->ClearAllF(); - for (int w=0; w<3; w++) if (fi->FFp(w) != &*fi) fi->SetF(w); - } - if (k==3) // disconnected single triangle (all borders): use catmull-clark (tree vertices, split it in 6 - { - fi->ClearAllF(); - fi->SetF(2); - nsplit++; - } - } - else { - // assuming is a part of quad (not a penta, etc), i.e. only one faux - FaceType *fa = &*fi; - int ea2 = BQ::FauxIndex(fa); // index of the only faux edge - FaceType *fb = fa->FFp(ea2); - int eb2 = fa->FFi(ea2); - assert(fb->FFp(eb2)==fa) ; - assert(fa->IsF(ea2)); - //assert(fb->IsF(eb2)); // reciprocal faux edge - - int ea0 = (ea2+1) %3; - int ea1 = (ea2+2) %3; - int eb0 = (eb2+1) %3; - int eb1 = (eb2+2) %3; - - // create new vert in center of faux edge - assert(nvi!=m.vert.end()); - VertexType *nv = &*nvi; nvi++; - // *nv = * fa->V0( ea2 ); - nv->ImportData(*(fa->V0( ea2 ) )); // lazy: copy everything from the old vertex - //nv->P() = ( fa->V(ea2)->P() + fa->V(ea0)->P() ) /2.0; - Interpolator::Apply(*(fa->V(ea2)),*(fa->V(ea0)),0.5,*nv); - // split faces: add 2 faces (one per side) - assert(nfi!=m.face.end()); - FaceType *fc = &*nfi; nfi++; - assert(nfi!=m.face.end()); - FaceType *fd = &*nfi; nfi++; - - fc->ImportData(*fa ); CopyTopology(fc,fa); // lazy: copy everything from the old vertex - fd->ImportData(*fb ); CopyTopology(fd,fb);// lazy: copy everything from the old vertex - - fa->V(ea2) = fc->V(ea0) = - fb->V(eb2) = fd->V(eb0) = nv ; - - fa->FFp(ea1)->FFp( fa->FFi(ea1) ) = fc; - fb->FFp(eb1)->FFp( fb->FFi(eb1) ) = fd; - - fa->FFp(ea1) = fc ; fa->FFp(ea2) = fd; - fa->FFi(ea1) = ea0; fa->FFi(ea2) = eb2; - fb->FFp(eb1) = fd ; fb->FFp(eb2) = fc; - fb->FFi(eb1) = eb0; fb->FFi(eb2) = ea2; - fc->FFp(ea0) = fa ; fc->FFp(ea2) = fb; - fc->FFi(ea0) = ea1; fc->FFi(ea2) = eb2; - fd->FFp(eb0) = fb ; fd->FFp(eb2) = fa; - fd->FFi(eb0) = eb1; fd->FFi(eb2) = ea2; - - // detect boundaries - bool ba = fa->FFp(ea0)==fa; - bool bc = fc->FFp(ea1)==fa; - bool bb = fb->FFp(eb0)==fb; - bool bd = fd->FFp(eb1)==fb; - - if (bc) fc->FFp(ea1)=fc; // repristinate boundary status - if (bd) fd->FFp(eb1)=fd; // of new faces - - fa->SetV(); - fb->SetV(); - fc->SetV(); - fd->SetV(); - - fa->ClearAllF(); - fb->ClearAllF(); - fc->ClearAllF(); - fd->ClearAllF(); - - fa->SetF( ea0 ); - fb->SetF( eb0 ); - fc->SetF( ea1 ); - fd->SetF( eb1 ); - - // fix faux mesh boundary... if two any consecutive, merge it in a quad - if (ba&&bc) { - fa->ClearAllF(); fa->SetF(ea1); - fc->ClearAllF(); fc->SetF(ea0); - ba = bc = false; - } - if (bc&&bb) { - fc->ClearAllF(); fc->SetF(ea2); - fb->ClearAllF(); fb->SetF(eb2); - bc = bb = false; - } - if (bb&&bd) { - fb->ClearAllF(); fb->SetF(eb1); - fd->ClearAllF(); fd->SetF(eb0); - bb = bd = false; - } - if (bd&&ba) { - fd->ClearAllF(); fd->SetF(eb2); - fa->ClearAllF(); fa->SetF(ea2); - bd = ba = false; - } - // remaninig boudaries will be fixed by splitting in the last pass - if (ba) nsplit++; - if (bb) nsplit++; - if (bc) nsplit++; - if (bd) nsplit++; - } - } - assert(nfi==m.face.end()); - assert(nvi==m.vert.end()); - - // now and there are no tris left, but there can be faces with ONE edge border & faux () - - - // last pass: add vertex on faux border faces... (if any) - if (nsplit>0) { - FaceIterator nfi = tri::Allocator::AddFaces(m,nsplit); - VertexIterator nvi = tri::Allocator::AddVertices(m,nsplit); - for (FaceIterator fi = m.face.begin(), fend = nfi; fi!=fend; fi++) if (!fi->IsD()) { - FaceType* fa = &*fi; - int ea2 = -1; // border and faux face (if any) - if (fa->FFp(0)==fa && fa->IsF(0) ) ea2=0; - if (fa->FFp(1)==fa && fa->IsF(1) ) ea2=1; - if (fa->FFp(2)==fa && fa->IsF(2) ) ea2=2; - - if (ea2 != -1) { // ea2 edge is naughty (border AND faux) - - int ea0 = (ea2+1) %3; - int ea1 = (ea2+2) %3; - - // create new vert in center of faux edge - VertexType *nv = &*nvi; nvi++; - //*nv = * fa->V0( ea2 ); - nv->ImportData(*(fa->V0( ea2 ) )); // lazy: copy everything from the old vertex - nv->P() = ( fa->V(ea2)->P() + fa->V(ea0)->P() ) /2.0; - Interpolator::Apply(*(fa->V(ea2)),*(fa->V(ea0)),0.5,*nv); - // split face: add 1 face - FaceType *fc = &*nfi; nfi++; - - fc->ImportData(*fa);CopyTopology(fc,fa); // lazy: copy everything from the old vertex - - fa->V(ea2) = fc->V(ea0) = nv ; - - fc->FFp(ea2) = fc; - - fa->FFp(ea1)->FFp( fa->FFi(ea1) ) = fc; - - fa->FFp(ea1) = fc ; - fa->FFi(ea1) = ea0; - fc->FFp(ea0) = fa ; fc->FFp(ea2) = fc; - fc->FFi(ea0) = ea1; - - if (fc->FFp(ea1)==fa) fc->FFp(ea1)=fc; // recover border status - - assert(fa->IsF(ea0) == fa->IsF(ea1) ); - bool b = fa->IsF(ea1); - - fa->ClearAllF(); - fc->ClearAllF(); - - if (b) { - fa->SetF( ea0 ); - fc->SetF( ea1 ); - } else { - fa->SetF( ea1 ); - fc->SetF( ea0 ); - } - } - } - } - - -} - - -// uses Catmull Clark to enforce quad only meshes -// each old edge (but not faux) is split in two. -static void MakePureByCatmullClark(MeshType &m){ - MakePureByRefine(m); - MakePureByRefine(m); - // done -} - -// Helper funcion: -// marks edge distance froma a given face. -// Stops at maxDist or at the distance when a triangle is found -static FaceType * MarkEdgeDistance(MeshType &m, FaceType *startF, int maxDist){ - assert(tri::HasPerFaceQuality(m)); - - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - fi->Q()=maxDist; - } - - FaceType * firstTriangleFound = NULL; - - startF->Q() = 0; - std::vector stack; - int stackPos=0; - stack.push_back(startF); - - while ( stackPosFFp(k); - int fq = int(f->Q()) + ( ! f->IsF(k) ); - if (fk->Q()> fq && fq <= maxDist) { - if (!fk->IsAnyF()) { firstTriangleFound = fk; maxDist = fq;} - fk->Q() = fq; - stack.push_back(fk); - } - } - } - return firstTriangleFound; -} - - -/* - given a tri-quad mesh, - uses edge rotates to make a tri move toward another tri and to merges them into a quad. - - Retunrs number of surviving triangles (0, or 1), or -1 if not done yet. - StepbyStep: makes just one step! - use it in a loop as long as it returns 0 or 1. - - maxdist is the maximal edge distance where to look for a companion triangle -*/ -static int MakePureByFlipStepByStep(MeshType &m, int maxdist=10000, int restart=false){ - - static FaceType *ta, *tb; // faces to be matched into a quad - - static int step = 0; // hack - - if (restart) { step=0; return false; } -if (step==0) { - - // find a triangular face ta - ta = NULL; - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - if (!fi->IsAnyF()) { ta=&*fi; break; } - } - if (!ta) return 0; // success: no triangle left (done?) - - - tb = MarkEdgeDistance(m,ta,maxdist); - if (!tb) return 1; // fail: no matching triagle found (increase maxdist?) - - step=1; - -} else { - int marriageEdge=-1; - bool done = false; - while (!done) { - - int bestScore = int(tb->Q()); - int edge = -1; - bool mustDoFlip; - - // select which edge to use - for (int k=0; k<3; k++) { - if (tb->FFp(k) == tb) continue; // border - - FaceType* tbk = tb->FFp(k); - - if (!tbk->IsAnyF()) {done=true; marriageEdge=k; break; } // found my match - - int back = tb->FFi(k); - int faux = BQ::FauxIndex(tbk); - int other = 3-back-faux; - - int scoreA = int(tbk->FFp(other)->Q()); - - FaceType* tbh = tbk->FFp(faux); - int fauxh = BQ::FauxIndex(tbh); - - int scoreB = int(tbh->FFp( (fauxh+1)%3 )->Q()); - int scoreC = int(tbh->FFp( (fauxh+2)%3 )->Q()); - - int scoreABC = std::min( scoreC, std::min( scoreA, scoreB ) ); - if (scoreABCFFp(edge)) ); - } - - FaceType* next = tb->FFp(edge)->FFp( BQ::FauxIndex(tb->FFp(edge)) ); - - // create new edge - next->ClearAllF(); - tb->FFp(edge)->ClearAllF(); - - // dissolve old edge - tb->SetF(edge); - tb->FFp(edge)->SetF( tb->FFi(edge) ); - tb->FFp(edge)->Q() = tb->Q(); - - tb = next; -break; - } - - if (marriageEdge!=-1) { - // consume the marriage (two tris = one quad) - assert(!(tb->IsAnyF())); - assert(!(tb->FFp(marriageEdge)->IsAnyF())); - tb->SetF(marriageEdge); - tb->FFp(marriageEdge)->SetF(tb->FFi(marriageEdge)); - - step=0; - } -} - return -1; // not done yet -} - -/* - given a tri-quad mesh, - uses edge rotates to make a tri move toward another tri and to merges them into a quad. - - maxdist is the maximal edge distance where to look for a companion triangle - - retunrs true if all triangles are merged (always, unless they are odd, or maxdist not enough). -*/ -static bool MakePureByFlip(MeshType &m, int maxdist=10000) -{ - MakePureByFlipStepByStep(m, maxdist, true); // restart - int res=-1; - while (res==-1) res = MakePureByFlipStepByStep(m, maxdist); - return res==0; -} - -/** - given a triangle mesh, makes it quad dominant by merging triangle pairs into quads - various euristics: - level = 0: maximally greedy. Leaves fewest triangles - level = 1: smarter: leaves more triangles, but makes better quality quads - level = 2: even more so (marginally) -*/ -static void MakeDominant(MeshType &m, int level){ - - assert(MeshType::HasPerFaceQuality()); - assert(MeshType::HasPerFaceFlags()); - - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) { - fi->ClearAllF(); - fi->Q() = 0; - } - - - MakeDominantPass (m); - if (level>0) MakeDominantPass (m); - if (level>1) MakeDominantPass (m); - if (level>0) MakeDominantPass (m); -} - -}; -}} // end namespace vcg::tri -#endif diff --git a/vcg/complex/trimesh/bitquad_optimization.h b/vcg/complex/trimesh/bitquad_optimization.h deleted file mode 100644 index 7ae503bb..00000000 --- a/vcg/complex/trimesh/bitquad_optimization.h +++ /dev/null @@ -1,404 +0,0 @@ -#ifndef _BITQUAD_OPTIMIZATION -#define _BITQUAD_OPTIMIZATION - -namespace vcg{namespace tri{ - -template -class BitQuadOptimization{ - -typedef typename BQ::MeshType MeshType; -typedef typename BQ::Pos Pos; - -typedef typename MeshType::ScalarType ScalarType; -typedef typename MeshType::CoordType CoordType; -typedef typename MeshType::FaceType FaceType; -typedef typename MeshType::FaceType* FaceTypeP; -typedef typename MeshType::VertexType VertexType; -typedef typename MeshType::FaceIterator FaceIterator; -typedef typename MeshType::VertexIterator VertexIterator; - -//typedef BitQuad BQ; // static class to make basic quad operatins - -public: - -// helper function: mark a quadface, setting Q at 0, and neight at .75, 0.5... -static void MarkFace(FaceType* f, MeshType &m){ - - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - fi->Q() = 1; - } - - for (int i=0; i<3; i++) { - for (int j=0; j<3; j++) f->FFp(i)->FFp(j)->Q() = 0.75; - } - for (int i=0; i<3; i++) { - f->FFp(i)->Q() = 0.50; - } - f->Q() = 0; - -} - -// helper function: mark a quadface, setting Q at 0, and neight at .75, 0.5... -static void MarkVertex(FaceType* f, int wedge, MeshType &m){ - - VertexType *v = f->V(wedge); - - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - if (fi->V0(0)==v || fi->V1(0)==v ||fi->V2(0)==v ) fi->Q() = 0; - // else fi->Q() = 1; - } - -} - -static bool MarkSmallestEdge(MeshType &m, bool perform) -{ - ScalarType min = std::numeric_limits::max(); - - FaceType *fa=NULL; int w=0; - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) - for (int k=0; k<3; k++) { - FaceType *f=&*fi; - - if (f->IsF(k)) continue; - if (f->FFp(k) == f ) continue; // skip borders - - ScalarType score; - - score = (f->P0(k) - f->P1(k)).Norm(); - if (scoreQ()=0.0; - fa->FFp(w)->Q()=0.0; - return true; - } - } - return false; -} - -static ScalarType Importance(const CoordType &p){ - //return ::proceduralImportance(p); - return 1; -} - -// returns: 0 if fail. 1 if edge. 2 if diag. -static int MarkSmallestEdgeOrDiag(MeshType &m, ScalarType edgeMult, bool perform, Pos* affected=NULL) -{ - ScalarType min = std::numeric_limits::max(); - - FaceType *fa=NULL; int w=0; bool counterDiag = false; - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) - for (int k=0; k<3; k++) { - FaceType *f=&*fi; - - if (f->FFp(k) >= f ) continue; // skip borders (==), and do it one per edge - - ScalarType score; - - score = (f->P0(k) - f->P1(k)).Norm(); - - ScalarType imp = Importance( (f->P0(k) + f->P1(k))/2 ); - - score /= imp; - - if (!f->IsF(k)) score*=edgeMult; // edges are supposed to be smaller! - - - - if (scoreIsF(k)) { // for diag faces, test counterdiag too - score = BQ::CounterDiag(f).Norm(); - score /= imp; - - if (scoreIsF(w)) { - if (counterDiag) { - if (BQ::CollapseCounterDiag(*fa, BQ::PosOnDiag(*fa,true), m , affected)) return 2; - } else { - if (BQ::CollapseDiag(*fa, BQ::PosOnDiag(*fa,false), m ,affected)) return 2; - } - } else { - if (BQ::CollapseEdge(*fa,w,m, affected)) return 1; - } - } else { - fa->Q()=0.0; - fa->FFp(w)->Q()=0.0; - if (fa->IsF(w)) return 2; else return 1; - } - } - return 0; -} - - -static void MarkSmallestDiag(MeshType &m) -{ - ScalarType min = std::numeric_limits::max(); - - FaceType *fa=NULL; - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - FaceType *f=&*fi; - - ScalarType score; - - score = BQ::Diag(f).Norm(); - if (scoreQ()=0.0; - fa->FFp(BQ::FauxIndex(fa))->Q()=0.0; - } - -} - - - -static bool IdentifyAndCollapseSmallestDiag(MeshType &m){ - ScalarType min = std::numeric_limits::max(); - - FaceType *fa=NULL; bool flip; - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - FaceType *f=&*fi; - - ScalarType score; - - score = BQ::Diag(f).Norm(); - if (scoreFFp(k),(fa->FFi(k)+2)%3, m )) return true; - - if (flip) { - if (!BQ::CheckFlipDiag(*fa) ) { - // I can't collapse (why?) - MarkFace(fa,m); - return false; - } else - BQ::CollapseCounterDiag(*fa, BQ::PosOnDiag(*fa,true), m ); - } - else { - BQ::CollapseDiag(*fa, BQ::PosOnDiag(*fa,false), m ); - } - return true; -} - - - -/* -seeks and removes all doublets (a pair of quads sharing two consecutive edges) -by merging them into a single quad (thus removing one vertex and two tri faces)- -Returns number of removed Doublets -*/ -static int RemoveDoublets(MeshType &m, Pos *p=NULL) -{ - int res=0; - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - fi->Q()=1; - for (int k=0; k<3; k++) { - if ( BQ::IsDoublet(*fi,k) ){ - res++; - BQ::RemoveDoublet(*fi,k,m,p); - if (fi->IsD()) break; // break wedge circle, if face disappeard - if (p) return res; - } - } - } - return res; -} - -/* -marks (Quality=0) and approx. counts profitable vertex rotations -(vertex rotations which make edge shorter -*/ -template -static int MarkVertexRotations(MeshType &m, Pos *affected=NULL) -{ - int res=0; - for (VertexIterator vi = m.vert.begin(); vi!=m.vert.end(); vi++) if (!vi->IsD()) vi->ClearV(); - if (!perform) - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) fi->Q()=1.0; - - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - - for (int k=0; k<3; k++) { - if (fi->V(k)->IsV()) continue; - if (BQ::TestVertexRotation(*fi,k)) { - res++; - fi->V(k)->SetV(); - if (!perform) { - res++; MarkVertex(&*fi, k, m); //fi->Q()=0; - } - else { - if (BQ::RotateVertex(*fi, k, m, affected)) res++; //fi->Q()=0; - if (affected) return res; // uncomment for only one rotation - } - } - } - } - return res; -} - -// mark (and count) all edges that are worth rotating -// if perform == true, actually rotate them -template -static int MarkEdgeRotations(MeshType &m, Pos *p=NULL) -{ - int count = 0; - - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) fi->Q()=1; - - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - //if (count>0) break; - for (int k=0; k<3; k++) { - if (fi->IsF(k)) continue; - if (fi->FFp(k)<= &*fi) continue; // only once per real (non faux) edge, and only for non border ones - int best = BQ::TestEdgeRotation(*fi, k); - if (perform) { - if (best==+1) if (BQ::template RotateEdge< true>(*fi, k, m, p)) count++; - if (best==-1) if (BQ::template RotateEdge(*fi, k, m, p)) count++; - if (p) if (count>0) return count; - } - else { - if (best!=0) { fi->Q()=0; fi->FFp(k)->Q()=0; count++; } - } - } - } - - return count; -} - -/* -marks (Quality=0) and approx. counts doublets (a pair of quads sharing two consecutive edges) -*/ -static int MarkDoublets(MeshType &m) -{ - int res=0; - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - fi->Q()=1; - for (int k=0; k<3; k++) { - if ( BQ::IsDoublet(*fi,k) ){ - res++; - if (fi->IsF((k+1)%3)) res++; // counts for a quad - fi->Q()=0; - } - } - } - assert (res%2==0); - return res/4; // return doublet pairs (approx, as a quad could be a part of many pairs) -} - -/* -marks (Quality=0) and counts singlets (vertex B in an A-B-A-C quad) -*/ -static int MarkSinglets(MeshType &m) -{ - int res=0; - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - fi->Q()=1; - for (int k=0; k<3; k++) { - if ( BQ::IsSinglet(*fi,k) ){ - res++; - fi->Q()=0; - } - } - } - assert (res%2==0); - return res/2; // return number of singlet pairs -} - -/* -deletes singlets, reutrns number of -*/ -static int RemoveSinglets(MeshType &m, Pos *p=NULL) -{ - int res=0; - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - for (int k=0; k<3; k++) { - if ( BQ::IsSinglet(*fi,k) ){ - res++; - BQ::RemoveSinglet(*fi,k,m, p); - if (p) return res; - break; - } - } - } - return res; // return singlet pairs (approx, as a quad could be a part of many pairs) -} - - -/* returns average quad quality, and assigns it to triangle quality -*/ -static ScalarType MeasureQuality(MeshType &m) -{ - assert(MeshType::HasPerFaceFlags()); - ScalarType res = 0; - int div = 0; - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - if (fi->IsAnyF()) { - - ScalarType q = BQ::quadQuality( &*fi, BQ::FauxIndex(&*fi) ); - - if (MeshType::HasPerFaceQuality()) fi->Q() = q; - res += q; - div++; - } - } - if (!div) return 0; else return res / div; -} - -}; -}} // end namespace vcg::tri - -#endif diff --git a/vcg/complex/trimesh/bitquad_support.h b/vcg/complex/trimesh/bitquad_support.h deleted file mode 100644 index e6c49d11..00000000 --- a/vcg/complex/trimesh/bitquad_support.h +++ /dev/null @@ -1,1180 +0,0 @@ -#ifndef VCG_BITQUAD_SUPPORT -#define VCG_BITQUAD_SUPPORT -#include -#include -#include -#include -#include -#include - -/** BIT-QUAD creation support: - a few basic operations to work with bit-quads simplices - (quads defined by faux edges over a tri mesh backbone) - - - [ basic operations: ] - - bool IsDoublet(const FaceType& f, int wedge) - void RemoveDoublet(FaceType &f, int wedge, MeshType& m) - - identifies and removed "Doublets" (pair of quads sharing two consecutive edges) - - bool IsSinglet(const FaceType& f, int wedge) - void RemoveSinglet(FaceType &f, int wedge, MeshType& m) - - void FlipDiag(FaceType &f) - - rotates the faux edge of a quad (quad only change internally) - - bool RotateEdge(FaceType& f, int w0a); - - rotate a quad edge (clockwise or counterclockwise, specified via template) - - bool RotateVertex(FaceType &f, int w0) - - rotate around a quad vertex ("wind-mill" operation) - - void CollapseDiag(FaceType &f, ... p , MeshType& m) - - collapses a quad on its diagonal. - - p identifies the pos of collapsed point - (as either the parametric pos on the diagonal, or a fresh coordtype) - - - [ helper functions: ] - - ScalarType quadQuality( ... ); - - returns the quality for a given quad - - (should be made into a template parameter for methods using it) - - currently measures how squared each angle is - - int FauxIndex(const FaceType* f); - - returns index of the only faux edge of a quad (otherwise, assert) - - int CountBitPolygonInternalValency(const FaceType& f, int wedge) - - returns valency of vertex in terms of polygons (quads, tris...) - - -*/ - -// these should become a parameter in the corresponding class -#define DELETE_VERTICES 1 -// Reason not to delete vertices: -// if not vertex TwoManyfold, the vertex could still be used elsewhere... - -// if one, use length to determine if rotations are profitable -// if zero, maximize conformal quality -#define LENGTH_CRITERION 1 - -namespace vcg{namespace tri{ - -/* simple geometric-interpolation mono-function class used -as a default template parameter to BitQuad class */ -template -class GeometricInterpolator{ -public: - typedef typename VertexType::ScalarType ScalarType; - static void Apply( const VertexType &a, const VertexType &b, ScalarType t, VertexType &res){ - /*assert (&a != &b);*/ - res.P() = a.P()*(1-t) + b.P()*(t); - if (a.IsB()||b.IsB()) res.SetB(); - } -}; - -template < - // first template parameter: the tri mesh (with face-edges flagged) - class _MeshType, - // second template parameter: used to define interpolations between points - class Interpolator = GeometricInterpolator -> -class BitQuad{ -public: - -typedef _MeshType MeshType; -typedef typename MeshType::ScalarType ScalarType; -typedef typename MeshType::CoordType CoordType; -typedef typename MeshType::FaceType FaceType; -typedef typename MeshType::FaceType* FaceTypeP; -typedef typename MeshType::VertexType VertexType; -typedef typename MeshType::FaceIterator FaceIterator; -typedef typename MeshType::VertexIterator VertexIterator; -typedef typename MeshType::VertexPointer VertexPointer; - -class Pos{ - FaceType *f; - int e; -public: - enum{ PAIR, AROUND , NOTHING } mode; - FaceType* &F(){return f;} - FaceType* F() const {return f;} - VertexType* V() {return f->V(e);} - const VertexType* cV() const {return f->V(e);} - int& E(){return e;} - int E() const {return e;} - - - Pos(){ f=NULL; e=0; mode=AROUND;} - - Pos(FaceType* _f, int _e){f=_f; e=_e;} - Pos NextE()const {return Pos(f, (e+1)%3); } - Pos PrevE(){return Pos(f, (e+2)%3); } - bool IsF(){return f->IsF(e);} - Pos FlipF(){return Pos(f->FFp(e), f->FFi(e)); } - -}; - - - -static void MarkFaceF(FaceType *f){ - f->V(0)->SetS(); - f->V(1)->SetS(); - f->V(2)->SetS(); - int i=FauxIndex(f); - f->FFp( i )->V2( f->FFi(i) )->SetS(); - f->V(0)->SetV(); - f->V(1)->SetV(); - f->V(2)->SetV(); - f->FFp( i )->V2( f->FFi(i) )->SetV(); -} - - -template -static bool RotateEdge(FaceType& f, int w0a, MeshType &m, Pos *affected=NULL){ - FaceType *fa = &f; - assert(! fa->IsF(w0a) ); - - VertexType *v0, *v1; - v0= fa->V0(w0a); - v1= fa->V1(w0a); - - int w1a = (w0a+1)%3; - int w2a = (w0a+2)%3; - - FaceType *fb = fa->FFp(w0a); - - MarkFaceF(fa); - MarkFaceF(fb); - - int w0b = fa->FFi(w0a); - int w1b = (w0b+1)%3; - int w2b = (w0b+2)%3; - - if (fa->IsF(w2a) == verse) { - if (!CheckFlipDiag(*fa)) return false; - FlipDiag(*fa); - // hack: recover edge index, so that (f, w0a) identifies the same edge as before - fa = fb->FFp(w0b); - w0a = fb->FFi(w0b); - } - - if (fb->IsF(w2b) == verse) { - if (!CheckFlipDiag(*fb)) return false; - FlipDiag(*fb); - } - - if (!CheckFlipEdge(*fa,w0a)) return false; - FlipEdge(*fa,w0a,m); - if (affected) { - affected->F() = fa; - affected->E() = (FauxIndex(fa)+2)%3; - affected->mode = Pos::PAIR; - } - return true; -} - -/* small helper function which returns the index of the only - faux index, assuming there is exactly one (asserts out otherwise) -*/ -static int FauxIndex(const FaceType* f){ - if (f->IsF(0)) return 0; - if (f->IsF(1)) return 1; - assert(f->IsF(2)); - return 2; -} - -// rotates the diagonal of a quad -static void FlipDiag(FaceType &f){ - int faux = FauxIndex(&f); - FaceType* fa = &f; - FaceType* fb = f.FFp(faux); - vcg::face::FlipEdge(f, faux); - // ripristinate faux flags - fb->ClearAllF(); - fa->ClearAllF(); - for (int k=0; k<3; k++) { - if (fa->FFp(k) == fb) fa->SetF(k); - if (fb->FFp(k) == fa) fb->SetF(k); - } -} - - -// given a vertex (i.e. a face and a wedge), -// this function tells us how the totale edge lenght around a vertex would change -// if that vertex is rotated -static ScalarType EdgeLenghtVariationIfVertexRotated(const FaceType &f, int w0) -{ - assert(!f.IsD()); - - ScalarType - before=0, // sum of quad edges (originating from v) - after=0; // sum of quad diag (orginating from v) - int guard = 0; - - // rotate arond vertex - const FaceType* pf = &f; - int pi = w0; - int n = 0; // vertex valency - int na = 0; - do { - ScalarType triEdge = (pf->P0(pi) - pf->P1(pi) ).Norm(); - if (pf->IsF(pi)) { after += triEdge; na++;} - else { before+= triEdge; n++; } - if ( pf->IsF((pi+1)%3)) { after += CounterDiag( pf ).Norm(); na++; } - - const FaceType *t = pf; - t = pf->FFp( pi ); - if (pf == t ) return std::numeric_limits::max(); // it's a mesh border! flee! - pi = pf->cFFi( pi ); - pi = (pi+1)%3; // FaceType::Next( pf->FFi( pi ) ); - pf = t; - assert(guard++<100); - } while (pf != &f); - assert (na == n); - return (after-before); -} - -// given a vertex (i.e. a face and a wedge), -// this function tells us how the totale edge lenght around a vertex would change -// if that vertex is rotated -static ScalarType QuadQualityVariationIfVertexRotated(const FaceType &f, int w0) -{ - assert(!f.IsD()); - - ScalarType - before=0, // sum of quad quality around v - after=0; // same after the collapse - int guard = 0; - - // rotate arond vertex - const FaceType* pf = &f; - int pi = w0; - int nb = 0; // vertex valency - int na = 0; - std::vector s; // 1 star around v - do { - // ScalarType triEdge = (pf->P0(pi) - pf->P1(pi) ).Norm(); - if (!pf->IsF(pi)) { - if ( pf->IsF((pi+1)%3)) { - s.push_back(pf->cFFp((pi+1)%3)->V2( pf->cFFi((pi+1)%3) )); - } else { - s.push_back( pf->V2(pi) ); - } - - s.push_back( pf->V1(pi) ); - } - - const FaceType *t = pf; - t = pf->FFp( pi ); - if (pf == t ) return std::numeric_limits::max(); // it's a mesh border! flee! - pi = pf->cFFi( pi ); - pi = (pi+1)%3; // FaceType::Next( pf->FFi( pi ) ); - pf = t; - assert(guard++<100); - } while (pf != &f); - - assert(s.size()%2==0); - int N = s.size(); - for (int i=0; iP(),s[j]->P(),s[k]->P(),f.P(w0) ); - after+=quadQuality( s[h]->P(),s[i]->P(),s[j]->P(),f.P(w0) ); - } - - assert (na == nb); - return (after-before); -} - -/* - const FaceType* pf = &f; - int pi = wedge; - int res = 0, guard=0; - do { - if (!pf->IsAnyF()) return false; // there's a triangle! - if (!pf->IsF(pi)) res++; - const FaceType *t = pf; - t = pf->FFp( pi ); - if (pf == t ) return false; - pi = pf->cFFi( pi ); - pi = (pi+1)%3; // FaceType::Next( pf->FFi( pi ) ); - pf = t; - assert(guard++<100); - } while (pf != &f); -*/ - -// given a vertex (i.e. a face and a wedge), -// this function tells us if it should be rotated or not -// (currently, we should iff it is shortened) -static bool TestVertexRotation(const FaceType &f, int w0) -{ - assert(!f.IsD()); - -#if (LENGTH_CRITERION) - // rotate vertex IFF this way edges become shorter: - return EdgeLenghtVariationIfVertexRotated(f,w0)<0; -#else - // rotate vertex IFF overall Quality increase -#endif - return QuadQualityVariationIfVertexRotated(f,w0)<0; -} - - -static bool RotateVertex(FaceType &f, int w0, MeshType &m, Pos *affected=NULL) -{ - - int guard = 0; - - FaceType* pf = &f; - int pi = w0; - int n = 0; // vertex valency - - if (pf->IsF((pi+2) % 3)) { - pi = (pi+2)%3; - // do one step back - int tmp = pf->FFi(pi); pf = pf->FFp(pi); pi = tmp; // flipF - } - - const FaceType* stopA = pf; - const FaceType* stopB = pf->FFp(FauxIndex(pf)); - - // rotate around vertex, flipping diagonals if necessary, - do { - bool mustFlip; - if (pf->IsF(pi)) { - // if next edge is faux, move on other side of quad - int tmp = (pf->FFi(pi)+1)%3; pf = pf->FFp(pi); pi = tmp; // flipF - mustFlip = false; - } - else { - mustFlip = true; - } - - FaceType *lastF = pf; - - int tmp = (pf->FFi(pi)+1)%3; pf = pf->FFp(pi); pi = tmp; // flipF - - if (mustFlip) { - if (!CheckFlipDiag(*lastF)) return false; // cannot flip?? - FlipDiag(*lastF); - } - MarkFaceF(pf); - } while (pf != stopA && pf!= stopB); - - // last pass: rotate arund vertex again, changing faux status - stopA=pf; - do { - int j = pi; - if (pf->IsF(j)) - { pf->ClearF(j); IncreaseValency(pf->V1(j)); } - else - { pf->SetF(j); DecreaseValencySimple(pf->V1(j),1); } - - j = (j+2)%3; - if (pf->IsF(j)) pf->ClearF(j); else pf->SetF(j); - int tmp = (pf->FFi(pi)+1)%3; pf = pf->FFp(pi); pi = tmp; // flipF flipV - } while (pf != stopA ); - - if (affected) { - affected->F() = pf; - affected->E()=pi; - } - return true; -} - - - - - -// flips the faux edge of a quad -static void FlipEdge(FaceType &f, int k, MeshType &m){ - assert(!f.IsF(k)); - FaceType* fa = &f; - FaceType* fb = f.FFp(k); - assert(fa!=fb); // else, rotating a border edge - - // backup prev other-quads-halves - FaceType* fa2 = fa->FFp( FauxIndex(fa) ); - FaceType* fb2 = fb->FFp( FauxIndex(fb) ); - - IncreaseValency( fa->V2(k) ); - IncreaseValency( fb->V2(f.FFi(k)) ); - //DecreaseValency( fa->V0(k) ); - //DecreaseValency( fa->V1(k) ); - DecreaseValency(fa, k ,m); - DecreaseValency(fa,(k+1)%3,m ); - - - vcg::face::FlipEdge(*fa, k); - - // ripristinate faux flags - fb->ClearAllF(); - fa->ClearAllF(); - for (int k=0; k<3; k++) { - //if (fa->FFp(k) == fa2) fa->SetF(k); - //if (fb->FFp(k) == fb2) fb->SetF(k); - if (fa->FFp(k)->IsF( fa->FFi(k) )) fa->SetF(k); - if (fb->FFp(k)->IsF( fb->FFi(k) )) fb->SetF(k); - } - -} - -// check if a quad diagonal can be topologically flipped -static bool CheckFlipDiag(FaceType &f){ - return (vcg::face::CheckFlipEdge(f, FauxIndex(&f) ) ); -} - -// given a face (part of a quad), returns its diagonal -static CoordType Diag(const FaceType* f){ - int i = FauxIndex(f); - return f->P1( i ) - f->P0( i ); -} - - -// given a face (part of a quad), returns other diagonal -static CoordType CounterDiag(const FaceType* f){ - int i = FauxIndex(f); - return f->cP2( i ) - f->cFFp( i )->cP2(f->cFFi(i) ) ; -} - -/* helper function: - collapses a single face along its faux edge. - Updates FF adj of other edges. */ -static void _CollapseDiagHalf(FaceType &f, int faux, MeshType& m) -{ - int faux1 = (faux+1)%3; - int faux2 = (faux+2)%3; - - FaceType* fA = f.FFp( faux1 ); - FaceType* fB = f.FFp( faux2 ); - - MarkFaceF(fA); - MarkFaceF(fB); - - int iA = f.FFi( faux1 ); - int iB = f.FFi( faux2 ); - - if (fA==&f && fB==&f) { - // both non-faux edges are borders: tri-face disappears, just remove the vertex - //if (DELETE_VERTICES) - //if (GetValency(f.V(faux2))==0) Allocator::DeleteVertex(m,*(f.V(faux2))); - } else { - if (fA==&f) { - fB->FFp(iB) = fB; fB->FFi(iB) = iB; - } else { - fB->FFp(iB) = fA; fB->FFi(iB) = iA; - } - - if (fB==&f) { - fA->FFp(iA) = fA; fA->FFi(iA) = iA; - } else { - fA->FFp(iA) = fB; fA->FFi(iA) = iB; - } - } - - - //DecreaseValency(&f,faux2,m); // update valency - //Allocator::DeleteFace(m,f); - -} - -static void RemoveDoublet(FaceType &f, int wedge, MeshType& m, Pos* affected=NULL){ - if (f.IsF((wedge+1)%3) ) { - VertexType *v = f.V(wedge); - FlipDiag(f); - // quick hack: recover wedge index after flip - if (f.V(0)==v) wedge = 0; - else if (f.V(1)==v) wedge = 1; - else { - assert(f.V(2)==v); - wedge = 2; - } - } - ScalarType k=(f.IsF(wedge))?1:0; - CollapseDiag(f, k, m, affected); - VertexType *v = f.V(wedge); -} - -static void RemoveSinglet(FaceType &f, int wedge, MeshType& m, Pos* affected=NULL){ - if (affected) affected->mode = Pos::NOTHING; // singlets leave nothing to update behind - - if (f.V(wedge)->IsB()) return; // hack: lets detect - - FaceType *fa, *fb; // these will die - FaceType *fc, *fd; // their former neight - fa = & f; - fb = fa->FFp(wedge); - int wa0 = wedge; - int wa1 = (wa0+1)%3 ; - int wa2 = (wa0+2)%3 ; - int wb0 = (fa->FFi(wa0)+1)%3; - int wb1 = (wb0+1)%3 ; - int wb2 = (wb0+2)%3 ; - assert (fb == fa->FFp( wa2 ) ); // otherwise, not a singlet - - // valency decrease - DecreaseValency(fa, wa1, m); - DecreaseValency(fa, wa2, m); - if (fa->IsF(wa0)) { - DecreaseValency(fa,wa2,m); // double decrease of valency on wa2 - } else { - DecreaseValency(fa,wa1,m); // double decrease of valency on wa1 - } - - // no need to MarkFaceF ! - - fc = fa->FFp(wa1); - fd = fb->FFp(wb1); - int wc = fa->FFi(wa1); - int wd = fb->FFi(wb1); - fc->FFp(wc) = fd; - fc->FFi(wc) = wd; - fd->FFp(wd) = fc; - fd->FFi(wd) = wc; - // faux status of survivors: unchanged - assert( ! ( fc->IsF( wc) ) ); - assert( ! ( fd->IsF( wd) ) ); - - Allocator::DeleteFace( m,*fa ); - Allocator::DeleteFace( m,*fb ); - - DecreaseValency(fa,wedge,m ); - //if (DELETE_VERTICES) - //if (GetValency(fa->V(wedge))==0) Allocator::DeleteVertex( m,*fa->V(wedge) ); -} - - -static bool TestAndRemoveDoublet(FaceType &f, int wedge, MeshType& m){ - if (IsDoublet(f,wedge)) { - RemoveDoublet(f,wedge,m); - return true; - } - return false; -} - -static bool TestAndRemoveSinglet(FaceType &f, int wedge, MeshType& m){ - if (IsSinglet(f,wedge)) { - RemoveSinglet(f,wedge,m); - return true; - } - return false; -} - -// given a face and a wedge, counts its valency in terms of quads (and triangles) -// uses only FF, assumes twomanyfold -// returns -1 if border -static int CountBitPolygonInternalValency(const FaceType& f, int wedge){ - const FaceType* pf = &f; - int pi = wedge; - int res = 0; - do { - if (!pf->IsF(pi)) res++; - const FaceType *t = pf; - t = pf->FFp( pi ); - if (pf == t ) return -1; - pi = (pi+1)%3; // FaceType::Next( pf->FFi( pi ) ); - pf = t; - } while (pf != &f); - return res; -} - -// given a face and a wedge, returns if it host a doubet -// assumes tri and quad only. uses FF topology only. -static bool IsDoubletFF(const FaceType& f, int wedge){ - const FaceType* pf = &f; - int pi = wedge; - int res = 0, guard=0; - do { - if (!pf->IsAnyF()) return false; // there's a triangle! - if (!pf->IsF(pi)) res++; - const FaceType *t = pf; - t = pf->FFp( pi ); - if (pf == t ) return false; - pi = pf->cFFi( pi ); - pi = (pi+1)%3; // FaceType::Next( pf->FFi( pi ) ); - pf = t; - assert(guard++<100); - } while (pf != &f); - return (res == 2); -} - -// version that uses vertex valency -static bool IsDoublet(const FaceType& f, int wedge){ - return (GetValency( f.V(wedge)) == 2) && (!f.V(wedge)->IsB() ) ; -} - -static bool IsDoubletOrSinglet(const FaceType& f, int wedge){ - return (GetValency( f.V(wedge)) <= 2) && (!f.V(wedge)->IsB() ) ; -} - -static bool RemoveDoubletOrSinglet(FaceType& f, int wedge, MeshType& m, Pos* affected=NULL){ - if (GetValency( f.V(wedge)) == 2) { RemoveDoublet(f,wedge,m,affected) ; return true; } - assert (GetValency( f.V(wedge)) == 1) ; - RemoveSinglet(f,wedge,m,affected) ; - return true; -} - -// given a face and a wedge, returns if it host a singlets -// assumes tri and quad only. uses FF topology only. -static bool IsSingletFF(const FaceType& f, int wedge){ - const FaceType* pf = &f; - int pi = wedge; - int res = 0, guard=0; - do { - if (!pf->IsAnyF()) return false; // there's a triangle! - if (!pf->IsF(pi)) res++; - const FaceType *t = pf; - t = pf->FFp( pi ); - if (pf == t ) return false; - pi = pf->cFFi( pi ); - pi = (pi+1)%3; // FaceType::Next( pf->FFi( pi ) ); - pf = t; - assert(guard++<100); - } while (pf != &f); - return (res == 1); -} - -// version that uses vertex valency -static bool IsSinglet(const FaceType& f, int wedge){ - return (GetValency( f.V(wedge) ) == 1) && (!f.V(wedge)->IsB() ) ; -} - -static bool CollapseEdgeDirect(FaceType &f, int w0, MeshType& m){ - FaceType * f0 = &f; - - assert( !f0->IsF(w0) ); - - VertexType *v0, *v1; - v0 = f0->V0(w0); - v1 = f0->V1(w0); - - if (!RotateVertex(*f0,w0,m)) return false; - - // quick hack: recover original wedge - if (f0->V(0) == v0) w0 = 0; - else if (f0->V(1) == v0) w0 = 1; - else if (f0->V(2) == v0) w0 = 2; - else assert(0); - - assert( f0->V1(w0) == v1 ); - assert( f0->IsF(w0) ); - - return CollapseDiag(*f0,PosOnDiag(*f0,false), m); -} - -// collapses an edge. Optional output pos can be iterated around to find affected faces -static bool CollapseEdge(FaceType &f, int w0, MeshType& m, Pos *affected=NULL){ - FaceTypeP f0 = &f; - assert(!f0->IsF(w0)); // don't use this method to collapse diag. - - if (IsDoubletOrSinglet(f,w0)) return false; //{ RemoveDoubletOrSinglet(f,w0,m, affected); return true;} - if (IsDoubletOrSinglet(f,(w0+1)%3)) return false; //{ RemoveDoubletOrSinglet(f,(w0+1)%3,m, affected); return true;} - - if (affected) { - int w1 = 3-w0-FauxIndex(f0); // the edge whihc is not the collapsed one nor the faux - affected->F() = f0->FFp(w1); - affected->E() = (f0->FFi(w1)+2+w1-FauxIndex(f0))%3; - } - - FaceTypeP f1 = f0->FFp(w0); - int w1 = f0->FFi(w0); - - assert(f0!=f1); // can't collapse border edges! - - // choose: rotate around V0 or around V1? - if ( - EdgeLenghtVariationIfVertexRotated(*f0,w0) - < - EdgeLenghtVariationIfVertexRotated(*f1,w1) - ) return CollapseEdgeDirect(*f0,w0,m); - else return CollapseEdgeDirect(*f1,w1,m); -} - - - -/** collapses a quad diagonal a-b - forming the new vertex in between the two old vertices. - if k == 0, new vertex is in a - if k == 1, new vertex is in b - if k == 0.5, new vertex in the middle, etc -*/ -static bool CollapseCounterDiag(FaceType &f, ScalarType interpol, MeshType& m, Pos* affected=NULL){ - if (!CheckFlipDiag(f)) return false; - FlipDiag(f); - return CollapseDiag(f,interpol,m,affected); -} - -// rotates around vertex -class Iterator{ -private: - typedef typename face::Pos FPos; - Pos start, cur; - bool over; -public: - Iterator(Pos& pos){ - if (pos.mode==Pos::NOTHING) {over = true; return; } - start = pos; //FPos(pos.F(), pos.E()); - if (start.F()->IsD()) { over = true; return;} - assert(!start.F()->IsD()); - if (pos.mode==Pos::AROUND) { - if (start.F()->IsF((start.E()+2)%3)) - { - int i = start.F()->FFi( start.E() ); - start.F() = start.F()->FFp( start.E() ); - start.E() = (i+1)%3; - } - } - cur=start; - over = false; - } - bool End() const { - return over; - } - void operator ++ () { - if (start.mode==Pos::PAIR) { - if (cur.F()!=start.F()) over=true; - int i = (cur.E()+2)%3; - cur.E() = (cur.F()->FFi( i )+1)%3; - cur.F() = cur.F()->FFp( i ); - } else { - if (cur.F()->IsF(cur.E())) { - // jump over faux diag - int i = cur.F()->FFi( cur.E() ); - cur.F() = cur.F()->FFp( cur.E() ); - cur.E() = (i+1)%3; - } - // jump over real edge - FaceType *f =cur.F()->FFp( cur.E() ); - if (f==cur.F()) over=true; // border found - cur.E() = (cur.F()->FFi( cur.E() ) +1 )%3; - cur.F() = f; - if (cur.F()==start.F()) over=true; - } - } - - Pos GetPos(){ - return cur; - } -}; - -static bool CollapseDiag(FaceType &f, ScalarType interpol, MeshType& m, Pos* affected=NULL){ - - FaceType* fa = &f; // fa lives - int fauxa = FauxIndex(fa); - - //if (IsDoubletOrSinglet(f,fauxa)) { RemoveDoubletOrSinglet(f,fauxa,m, affected); return true;} -// if (IsDoubletOrSinglet(f,(fauxa+2)%3)) { RemoveDoubletOrSinglet(f,(fauxa+2)%3,m, affected); return true;} - if (IsDoubletOrSinglet(f,(fauxa+2)%3)) return false; - if (IsDoubletOrSinglet(*(f.FFp(fauxa)),(f.FFi(fauxa)+2)%3)) return false; - - if (affected) { - int w1 = (fauxa+2)%3; // any edge but not the faux - affected->F() = fa->FFp(w1); - affected->E() = fa->FFi(w1); - if (affected->F() == fa){ - int w1 = (fauxa+1)%3; // any edge but not the faux - affected->F() = fa->FFp(w1); - affected->E() = (fa->FFi(w1)+2)%3; - } - } - - FaceType* fb = fa->FFp(fauxa); // fb dies - assert (fb!=fa); // otherwise, its a singlet - int fauxb = FauxIndex(fb); - - VertexType* va = fa->V(fauxa); // va lives - VertexType* vb = fb->V(fauxb); // vb dies - - Interpolator::Apply( *(f.V0(fauxa)), *(f.V1(fauxa)), interpol, *va); - - bool border = false; - int val =0; // number of faces around vb, which dies - - // update FV... - - // rotate around vb, (same-sense-as-face)-wise - int pi = fauxb; - FaceType* pf = fb; /* pf, pi could be put in a Pos p(pb, fauxb) */ - do { - //pf->V(pi) = va; - if (((pf->V2(pi) == va)||(pf->V1(pi) == va)) - &&(pf!=fa)&&(pf!=fb)) - return false; - pi=(pi+2)%3; - FaceType *t = pf->FFp(pi); - if (t==pf) { border= true; break; } - pi = pf->FFi(pi); - pf = t; - } while ((pf!=fb)); - - pi = fauxb; - pf = fb; - - do { - pf->V(pi) = va; - - pi=(pi+2)%3; - FaceType *t = pf->FFp(pi); - if (t==pf) { border= true; break; } - if (!pf->IsF(pi)) val++; - pi = pf->FFi(pi); - pf = t; - } while (pf!=fb); - - // of found a border, also rotate around vb, (counter-sense-as-face)-wise - if (border) { - val++; - int pi = fauxa; - FaceType* pf = fa; /* pf, pi could be a Pos p(pf, pi) */ - do { - pi=(pi+1)%3; - pf->V(pi) = va; - FaceType *t = pf->FFp(pi); - if (t==pf) break; - if (!pf->IsF(pi)) val++; - pi = pf->FFi(pi); - pf = t; - } while (pf!=fb); - } - - // update FF, delete faces - _CollapseDiagHalf(*fb, fauxb, m); - _CollapseDiagHalf(*fa, fauxa, m); - - SetValency(va, GetValency(va)+val-2); - DecreaseValency(fb,(fauxb+2)%3,m); // update valency - DecreaseValency(fa,(fauxa+2)%3,m); // update valency - Allocator::DeleteFace(m,*fa); - Allocator::DeleteFace(m,*fb); - - //assert(val == GetValency(vb)); - - - DecreaseValencyNoSingletTest(vb, val, m); - // note: don't directly kill vb. In non-twomanifold, it could still be referecned - // but: don't hunt for doublets either. - - assert(GetValency(vb)!=1 || vb->IsB()); - // if this asserts, you are in trouble. - // It means that the vertex that was supposed to die is still attached - // somewhere else (non-twomanifold) - // BUT in its other attachments it is a singlet, and that singlet cannot be - // found now (would require VF) - - - return true; -} - - - - -// helper function: find a good position on a diag to collapse a point -// currently, it is point in the middle, -// unless a mixed border-non border edge is collapsed, then it is an exreme -static ScalarType PosOnDiag(const FaceType& f, bool counterDiag){ - bool b0, b1, b2, b3; // which side of the quads are border - - const FaceType* fa=&f; - int ia = FauxIndex(fa); - const FaceType* fb=fa->cFFp(ia); - int ib = fa->cFFi(ia); - - b0 = fa->FFp((ia+1)%3) == fa; - b1 = fa->FFp((ia+2)%3) == fa; - b2 = fb->FFp((ib+1)%3) == fb; - b3 = fb->FFp((ib+2)%3) == fb; - - if (counterDiag) { - if ( (b0||b1) && !(b2||b3) ) return 1; - if ( !(b0||b1) && (b2||b3) ) return 0; - } else { - if ( (b1||b2) && !(b3||b0) ) return 0; - if ( !(b1||b2) && (b3||b0) ) return 1; - } - //if (f->FF( FauxIndex(f) )->IsB( - return 0.5f; -} - -// trick! hide valency in flags -typedef enum { VALENCY_FLAGS = 24 } ___; // this bit and the 4 successive one are devoted to store valency - -static void SetValency(VertexType *v, int n){ - //v->Q() = n; - assert(n>=0 && n<=255); - v->Flags()&= ~(255<Flags()|= n<cQ()); - return ( v->Flags() >> (VALENCY_FLAGS) ) & 255; -} - -static void IncreaseValency(VertexType *v, int dv=1){ -#ifdef NDEBUG - v->Flags() += dv<Flags() -= dv<V(wedge); - int val = GetValency(v)-1; - SetValency( v, val ); - if (val==0) Allocator::DeleteVertex(m,*v); - if (val==1) // singlet! - RemoveSinglet(*f,wedge,m); // this could be recursive... -} - -// decrease valency, remove unreferenced vertices too, but don't check for singlets... -static void DecreaseValencyNoSingletTest(VertexType *v, int dv, MeshType &m){ - int val = GetValency(v)-dv; - SetValency( v, val ); - if (DELETE_VERTICES) - if (val==0) Allocator::DeleteVertex(m,*v); -} - -static void DecreaseValencySimple(VertexType *v, int dv){ - int val = GetValency(v)-dv; - SetValency( v, val ); -} - -static void UpdateValencyInFlags(MeshType& m){ - for (VertexIterator vi = m.vert.begin(); vi!=m.vert.end(); vi++) if (!vi->IsD()) { - SetValency(&*vi,0); - } - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - for (int w=0; w<3; w++) - if (!fi->IsF(w)) - IncreaseValency( fi->V(w)); - } -} - -static void UpdateValencyInQuality(MeshType& m){ - for (VertexIterator vi = m.vert.begin(); vi!=m.vert.end(); vi++) if (!vi->IsD()) { - vi->Q() = 0; - } - - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - for (int w=0; w<3; w++) - fi->V(w)->Q() += (fi->IsF(w)||fi->IsF((w+2)%3) )? 0.5f:1; - } -} - -static bool HasConsistentValencyFlag(MeshType &m) { - UpdateValencyInQuality(m); - bool isok=true; - for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - for (int k=0; k<3; k++) - if (GetValency(fi->V(k))!=fi->V(k)->Q()){ - MarkFaceF(&*fi); - isok=false; - } - } - return isok; -} - -// helper function: -// returns quality of a given (potential) quad -static ScalarType quadQuality(FaceType *f, int edge){ - - CoordType - a = f->V0(edge)->P(), - b = f->FFp(edge)->V2( f->FFi(edge) )->P(), - c = f->V1(edge)->P(), - d = f->V2(edge)->P(); - - return quadQuality(a,b,c,d); - -} - -/** -helper function: -given a quad edge, retruns: - 0 if that edge should not be rotated - +1 if it should be rotated clockwise (+1) - -1 if it should be rotated counterclockwise (-1) -Currently an edge is rotated iff it is shortened by that rotations -(shortcut criterion) -*/ -static int TestEdgeRotation(const FaceType &f, int w0, ScalarType *gain=NULL) -{ - const FaceType *fa = &f; - assert(! fa->IsF(w0) ); - ScalarType q0,q1,q2; - CoordType v0,v1,v2,v3,v4,v5; - int w1 = (w0+1)%3; - int w2 = (w0+2)%3; - - v0 = fa->P(w0); - v3 = fa->P(w1); - - if (fa->IsF(w2) ) { - v1 = fa->cFFp(w2)->V2( fa->cFFi(w2) )->P(); - v2 = fa->P(w2); - } else { - v1 = fa->P(w2); - v2 = fa->cFFp(w1)->V2( fa->cFFi(w1) )->P(); - } - - const FaceType *fb = fa->cFFp(w0); - w0 = fa->cFFi(w0); - - w1 = (w0+1)%3; - w2 = (w0+2)%3; - if (fb->IsF(w2) ) { - v4 = fb->cFFp(w2)->V2( fb->cFFi(w2) )->P(); - v5 = fb->P(w2); - } else { - v4 = fb->P(w2); - v5 = fb->cFFp(w1)->V2( fb->cFFi(w1) )->P(); - } - - -#if (!LENGTH_CRITERION) - // max overall CONFORMAL quality criterion: - q0 = quadQuality(v0,v1,v2,v3) + quadQuality(v3,v4,v5,v0); // keep as is? - q1 = quadQuality(v1,v2,v3,v4) + quadQuality(v4,v5,v0,v1); // rotate CW? - q2 = quadQuality(v5,v0,v1,v2) + quadQuality(v2,v3,v4,v5); // rotate CCW? - - if (q0>=q1 && q0>=q2) return 0; - if (q1>=q2) return 1; - -#else - // min distance (shortcut criterion) - q0 = (v0 - v3).SquaredNorm(); - q1 = (v1 - v4).SquaredNorm(); - q2 = (v5 - v2).SquaredNorm(); - - if (q0<=q1 && q0<=q2) return 0; // there's no rotation shortening this edge - - //static int stop=0; - //static int go=0; - //if ((stop+go)%100==99) printf("Stop: %4.1f%%\n",(stop*100.0/(stop+go)) ); - - if (q1<=q2) { - if (gain) *gain = sqrt(q1)-sqrt(q0); - // test: two diagonals should become shorter (the other two reamin the same) - if ( - (v0-v2).SquaredNorm() < (v4-v2).SquaredNorm() || - (v3-v5).SquaredNorm() < (v1-v5).SquaredNorm() - ) { - //stop++; - return 0; - } - //go++; - return 1; - } - - { - if (gain) *gain = sqrt(q2)-sqrt(q0); - // diagonal test, as above: - if ( - (v0-v4).SquaredNorm() < (v2-v4).SquaredNorm() || - (v3-v1).SquaredNorm() < (v5-v1).SquaredNorm() - ) { - //stop++; - return 0; - } - //go++; - return -1; - } -#endif -} - -private: - -// helper function: -// returns quality of a quad formed by points a,b,c,d -// quality is computed as "how squared angles are" -static ScalarType quadQuality(const CoordType &a, const CoordType &b, const CoordType &c, const CoordType &d){ - ScalarType score = 0; - score += 1 - math::Abs( Cos( a,b,c) ); - score += 1 - math::Abs( Cos( b,c,d) ); - score += 1 - math::Abs( Cos( c,d,a) ); - score += 1 - math::Abs( Cos( d,a,b) ); - return score / 4; -} - - - - -private: - -// helper function: -// cos of angle abc. This should probably go elsewhere -static ScalarType Cos(const CoordType &a, const CoordType &b, const CoordType &c ) -{ - CoordType - e0 = b - a, - e1 = b - c; - ScalarType d = (e0.Norm()*e1.Norm()); - if (d==0) return 0.0; - return (e0*e1)/d; -} -public: -/** - Generic quad triangulation function. - It take in input 4 vertex pointrs and rotate them so that a simple fan triangulation is Ok. - It uses geometric criteria for avoiding bad shaped triangles, and folds - and it use an internal set of already created diagonal to avoid the creation of non manifold situations. - At the begin you shoud call this function with an empty vector to reset the set of existing diagonals. - */ -static void QuadTriangulate(std::vector &q) -{ - typedef typename std::set > diagSetType; - static diagSetType diagSet; // the set of already created diagonals - if(q.size()!=4) - { - diagSet.clear(); - return; - } - const CoordType &P0=q[0]->cP(); - const CoordType &P1=q[1]->cP(); - const CoordType &P2=q[2]->cP(); - const CoordType &P3=q[3]->cP(); - - CoordType N00 = Normal(P0,P1,P2); - CoordType N01 = Normal(P0,P2,P3); - CoordType N10 = Normal(P1,P2,P3); - CoordType N11 = Normal(P1,P3,P0); - - ScalarType Angle0Rad=Angle(N00,N01); - ScalarType Angle1Rad=Angle(N10,N11); - - // QualityRadii is inradius/circumradius; bad when close to zero. - // swap diagonal if the worst triangle improve. - bool qualityImprove = std::min(QualityRadii(P0,P1,P2),QualityRadii(P0,P2,P3)) < std::min(QualityRadii(P1,P2,P3),QualityRadii(P1,P3,P0)); - bool swapCauseFlip = (Angle1Rad > M_PI/2.0) && (Angle0Rad res; - if(q[0] -#include -#include -#include -namespace vcg { - -/** Class Boundary. -This is class for exporting the boundary of a d simplicial complex as a d-1 simplicial complex -*/ -class Boundary{ -public: - -///this function build a triangle mesh using the same pointers to the tetrahedral mesh vertex -template -static void OfTetramesh(TetraContainer &tetra,TriangleMeshType &trim) -{ -typedef typename TetraContainer::iterator TetraIterator; -typedef typename TetraContainer::value_type TetraVertexType; -typedef typename TriangleMeshType::FaceType FaceType; -typedef typename TriangleMeshType::VertexType TriangleVertexType; - -TetraIterator ti; -TetraVertexType *v0; -TetraVertexType *v2; - -trim.Clear(); -for (ti=tetra.begin();tiIsD())) - { - if ((ti->IsBorderF(0))||(ti->IsBorderF(1))||(ti->IsBorderF(2))||(ti->IsBorderF(3))) - for (int i=0;i<4;i++) - if (ti->IsBorderF(i)) - { - FaceType f=FaceType(); - f.ClearFlags(); - f.V(0)=(TriangleVertexType*)ti->V(Tetra::VofF(i,0)); - f.V(1)=(TriangleVertexType*)ti->V(Tetra::VofF(i,1)); - f.V(2)=(TriangleVertexType*)ti->V(Tetra::VofF(i,2)); - trim.face.push_back(f); - } - } - } -} - -template -struct InsertedV{ - -typedef typename TriVertexType::FaceType FaceType; -InsertedV( TriVertexType *_v, FaceType* _f,int _z):v(_v),f(_f),z(_z){} - -TriVertexType *v; -FaceType* f; -int z; - -const bool operator <(const InsertedV & o){ -return (v -static void OfTetrameshCopy(TetraContainer &tetra,TriangleMeshType &trim) -{ - typedef typename TetraContainer::iterator TetraIterator; - typedef typename TetraContainer::value_type::VertexType TetraVertexType; - typedef typename TriangleMeshType::FaceType FaceType; - typedef typename TriangleMeshType::FaceIterator FaceIterator; - typedef typename TriangleMeshType::VertexIterator TriVertexIterator; - typedef typename TriangleMeshType::VertexType TriVertexType; - - vector > newVertices; - typename vector >::iterator curr,next; - TriVertexIterator vi; - vector redirect; - - OfTetramesh(tetra,trim); - - FaceIterator fi; - - for(fi = trim.face.begin(); fi != trim.face.end(); ++fi){ - newVertices.push_back(InsertedV( (*fi).V(0),&(*fi),0)); - newVertices.push_back(InsertedV( (*fi).V(1),&(*fi),1)); - newVertices.push_back(InsertedV( (*fi).V(2),&(*fi),2)); - } - -sort(newVertices.begin(),newVertices.end()); - - -int pos = 0; -curr = next = newVertices.begin(); -while( next != newVertices.end()){ - if((*curr)!=(*next)) - pos++; - (*next).f->V( (*next).z) = (TriVertexType*)pos; - curr = next; - next++; -} - -typename vector >::iterator newE = unique(newVertices.begin(),newVertices.end()); -for(curr = newVertices.begin();curr!= newE;++curr) - trim.vert.push_back(*((*curr).v)); - -for(vi = trim.vert.begin(); vi != trim.vert.end(); ++vi) - redirect.push_back(&(*vi)); - -for(fi = trim.face.begin(); fi != trim.face.end(); ++fi){ - (*fi).V(0) = redirect[(int)(*fi).V(0)]; - (*fi).V(1) = redirect[(int)(*fi).V(1)]; - (*fi).V(2) = redirect[(int)(*fi).V(2)]; - } -trim.vn = trim.vert.size(); -trim.fn = trim.face.size(); -} - -};// End class -} // End namespace - - -#endif diff --git a/vcg/complex/trimesh/clean.h b/vcg/complex/trimesh/clean.h deleted file mode 100644 index 7a3dce83..00000000 --- a/vcg/complex/trimesh/clean.h +++ /dev/null @@ -1,1529 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ - -#ifndef __VCGLIB_CLEAN -#define __VCGLIB_CLEAN - -// Standard headers -#include -#include -#include - -// VCG headers -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace vcg { - namespace tri{ -template -class ConnectedIterator -{ - public: - typedef ConnectedMeshType MeshType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::FacePointer FacePointer; - typedef typename MeshType::FaceIterator FaceIterator; - typedef typename MeshType::ConstFaceIterator ConstFaceIterator; - typedef typename MeshType::FaceContainer FaceContainer; - - -public: - void operator ++() - { - FacePointer fpt=sf.top(); - sf.pop(); - for(int j=0;j<3;++j) - if( !face::IsBorder(*fpt,j) ) - { - FacePointer l=fpt->FFp(j); - if( !tri::IsMarked(*mp,l) ) - { - tri::Mark(*mp,l); - sf.push(l); - } - } -} - - void start(MeshType &m, FacePointer p) - { - mp=&m; - while(!sf.empty()) sf.pop(); - UnMarkAll(m); - assert(p); - assert(!p->IsD()); - tri::Mark(m,p); - sf.push(p); - } - bool completed() { - return sf.empty(); - } - - FacePointer operator *() - { - return sf.top(); - } -private: - std::stack sf; - MeshType *mp; -}; - - - /// - /** \addtogroup trimesh */ - /*@{*/ - /// Class of static functions to clean/correct/restore meshs. - template - class Clean - { - - public: - typedef CleanMeshType MeshType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::ConstVertexIterator ConstVertexIterator; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::FacePointer FacePointer; - typedef typename MeshType::FaceIterator FaceIterator; - typedef typename MeshType::ConstFaceIterator ConstFaceIterator; - typedef typename MeshType::FaceContainer FaceContainer; - typedef typename vcg::Box3 Box3Type; - - typedef GridStaticPtr TriMeshGrid; - typedef Point3 Point3x; - - //TriMeshGrid gM; - //FaceIterator fi; - //FaceIterator gi; - //vcg::face::Pos he; - //vcg::face::Pos hei; - - /* classe di confronto per l'algoritmo di eliminazione vertici duplicati*/ - class RemoveDuplicateVert_Compare{ - public: - inline bool operator()(VertexPointer const &a, VertexPointer const &b) - { - return (*a).cP() < (*b).cP(); - } - }; - - - /** This function removes all duplicate vertices of the mesh by looking only at their spatial positions. - Note that it does not update any topology relation that could be affected by this like the VT or TT relation. - the reason this function is usually performed BEFORE building any topology information. - */ - static int RemoveDuplicateVertex( MeshType & m, bool RemoveDegenerateFlag=true) // V1.0 - { - if(m.vert.size()==0 || m.vn==0) return 0; - - std::map mp; - size_t i,j; - VertexIterator vi; - int deleted=0; - int k=0; - size_t num_vert = m.vert.size(); - std::vector perm(num_vert); - for(vi=m.vert.begin(); vi!=m.vert.end(); ++vi, ++k) - perm[k] = &(*vi); - - RemoveDuplicateVert_Compare c_obj; - - std::sort(perm.begin(),perm.end(),c_obj); - - j = 0; - i = j; - mp[perm[i]] = perm[j]; - ++i; - for(;i!=num_vert;) - { - if( (! (*perm[i]).IsD()) && - (! (*perm[j]).IsD()) && - (*perm[i]).P() == (*perm[j]).cP() ) - { - VertexPointer t = perm[i]; - mp[perm[i]] = perm[j]; - ++i; - Allocator::DeleteVertex(m,*t); - deleted++; - } - else - { - j = i; - ++i; - } - } - FaceIterator fi; - for(fi = m.face.begin(); fi!=m.face.end(); ++fi) - if( !(*fi).IsD() ) - for(k = 0; k < 3; ++k) - if( mp.find( (typename MeshType::VertexPointer)(*fi).V(k) ) != mp.end() ) - { - (*fi).V(k) = &*mp[ (*fi).V(k) ]; - } - - if(RemoveDegenerateFlag) RemoveDegenerateFace(m); - return deleted; - } - - class SortedTriple - { - public: - SortedTriple() {} - SortedTriple(unsigned int v0, unsigned int v1, unsigned int v2,FacePointer _fp) - { - v[0]=v0;v[1]=v1;v[2]=v2; - fp=_fp; - std::sort(v,v+3); - } - bool operator < (const SortedTriple &p) const - { - return (v[2]!=p.v[2])?(v[2] fvec; - for(fi=m.face.begin();fi!=m.face.end();++fi) - if(!(*fi).IsD()) - { - fvec.push_back(SortedTriple( tri::Index(m,(*fi).V(0)), - tri::Index(m,(*fi).V(1)), - tri::Index(m,(*fi).V(2)), - &*fi)); - } - assert (size_t(m.fn) == fvec.size()); - //for(int i=0;i::DeleteFace(m, *(fvec[i].fp) ); - //qDebug("deleting face %i (pos in fvec %i)",tri::Index(m,fvec[i].fp) ,i); - } - } - return total; - } - /** This function removes that are not referenced by any face. The function updates the vn counter. - @param m The mesh - @return The number of removed vertices - */ - static int RemoveUnreferencedVertex( MeshType& m, bool DeleteVertexFlag=true) // V1.0 - { - FaceIterator fi; - VertexIterator vi; - int referredBit = VertexType::NewBitFlag(); - - int j; - int deleted = 0; - - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - (*vi).ClearUserBit(referredBit); - - for(fi=m.face.begin();fi!=m.face.end();++fi) - if( !(*fi).IsD() ) - for(j=0;j<3;++j) - (*fi).V(j)->SetUserBit(referredBit); - - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - if( (!(*vi).IsD()) && (!(*vi).IsUserBit(referredBit))) - { - if(DeleteVertexFlag) Allocator::DeleteVertex(m,*vi); - ++deleted; - } - VertexType::DeleteBitFlag(referredBit); - return deleted; - } - - /** - Degenerate vertices are vertices that have coords with invalid floating point values, - All the faces incident on deleted vertices are also deleted - */ - static int RemoveDegenerateVertex(MeshType& m) - { - VertexIterator vi; - int count_vd = 0; - - for(vi=m.vert.begin(); vi!=m.vert.end();++vi) - if(math::IsNAN( (*vi).P()[0]) || - math::IsNAN( (*vi).P()[1]) || - math::IsNAN( (*vi).P()[2]) ) - { - count_vd++; - Allocator::DeleteVertex(m,*vi); - } - - FaceIterator fi; - int count_fd = 0; - - for(fi=m.face.begin(); fi!=m.face.end();++fi) - if(!(*fi).IsD()) - if( (*fi).V(0)->IsD() || - (*fi).V(1)->IsD() || - (*fi).V(2)->IsD() ) - { - count_fd++; - Allocator::DeleteFace(m,*fi); - } - return count_vd; - } - - /** - Degenerate faces are faces that are Topologically degenerate, - i.e. have two or more vertex reference that link the same vertex - (and not only two vertexes with the same coordinates). - All Degenerate faces are zero area faces BUT not all zero area faces are degenerate. - We do not take care of topology because when we have degenerate faces the - topology calculation functions crash. - */ - static int RemoveDegenerateFace(MeshType& m) - { - FaceIterator fi; - int count_fd = 0; - - for(fi=m.face.begin(); fi!=m.face.end();++fi) - if(!(*fi).IsD()) - { - if((*fi).V(0) == (*fi).V(1) || - (*fi).V(0) == (*fi).V(2) || - (*fi).V(1) == (*fi).V(2) ) - { - count_fd++; - Allocator::DeleteFace(m,*fi); - } - } - return count_fd; - } - - static int RemoveNonManifoldVertex(MeshType& m) - { - /*int count_vd = */ - CountNonManifoldVertexFF(m,true); - /*int count_fd = */ - tri::UpdateSelection::FaceFromVertexLoose(m); - int count_removed = 0; - FaceIterator fi; - for(fi=m.face.begin(); fi!=m.face.end();++fi) - if(!(*fi).IsD() && (*fi).IsS()) - Allocator::DeleteFace(m,*fi); - VertexIterator vi; - for(vi=m.vert.begin(); vi!=m.vert.end();++vi) - if(!(*vi).IsD() && (*vi).IsS()) { - ++count_removed; - Allocator::DeleteVertex(m,*vi); - } - return count_removed; - } - - - /// Removal of faces that were incident on a non manifold edge. - static int SplitNonManifoldVertex(MeshType& m) - { - FaceIterator fi; - int count_sv = 0; // split vertex counter - typedef std::pair FaceInt; - - std::vector > >ToSplitVec; - - SelectionStack ss(m); - ss.push(); - CountNonManifoldVertexFF(m,true); - UpdateFlags::VertexClearV(m); - for (fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) - { - for(int i=0;i<3;i++) - if((*fi).V(i)->IsS() && !(*fi).V(i)->IsV()) - { - (*fi).V(i)->SetV(); - face::Pos startPos(&*fi,i); - face::Pos curPos = startPos; - std::set faceSet; - do - { - faceSet.insert(make_pair(curPos.F(),curPos.VInd())); - curPos.NextE(); - } while (curPos != startPos); - - ToSplitVec.push_back(make_pair((*fi).V(i),std::vector())); - - typename std::set::const_iterator iii; - - for(iii=faceSet.begin();iii!=faceSet.end();++iii) - ToSplitVec.back().second.push_back(*iii); - } - } - ss.pop(); - // Second step actually add new vertices and split them. - typename tri::Allocator::template PointerUpdater pu; - VertexIterator firstVp = tri::Allocator::AddVertices(m,ToSplitVec.size(),pu); - for(int i =0;iImportData(*np); - for(int j=0;jV(ff.second)=&*firstVp; - } - firstVp++; - } - - return ToSplitVec.size(); - } - - - // Auxiliary function for sorting the non manifold faces according to their area. Used in RemoveNonManifoldFace - struct CompareAreaFP { - bool operator ()(FacePointer const& f1, FacePointer const& f2) const { - return DoubleArea(*f1) < DoubleArea(*f2); - } - }; - - /// Removal of faces that were incident on a non manifold edge. - static int RemoveNonManifoldFace(MeshType& m) - { - FaceIterator fi; - int count_fd = 0; - std::vector ToDelVec; - - for(fi=m.face.begin(); fi!=m.face.end();++fi) - if (!fi->IsD()) - { - if ((!IsManifold(*fi,0))|| - (!IsManifold(*fi,1))|| - (!IsManifold(*fi,2))) - ToDelVec.push_back(&*fi); - } - - std::sort(ToDelVec.begin(),ToDelVec.end(),CompareAreaFP()); - - for(size_t i=0;iIsD()) - { - FaceType &ff= *ToDelVec[i]; - if ((!IsManifold(ff,0))|| - (!IsManifold(ff,1))|| - (!IsManifold(ff,2))) - { - for(int j=0;j<3;++j) - if(!face::IsBorder(ff,j)) - vcg::face::FFDetach(ff,j); - - Allocator::DeleteFace(m,ff); - count_fd++; - } - } - } - return count_fd; - } - - /* - The following functions remove faces that are geometrically "bad" according to edges and area criteria. - They remove the faces that are out of a given range of area or edges (e.g. faces too large or too small, or with edges too short or too long) - but that could be topologically correct. - These functions can optionally take into account only the selected faces. - */ - template - static int RemoveFaceOutOfRangeAreaSel(MeshType& m, ScalarType MinAreaThr=0, ScalarType MaxAreaThr=(std::numeric_limits::max)()) - { - FaceIterator fi; - int count_fd = 0; - MinAreaThr*=2; - MaxAreaThr*=2; - for(fi=m.face.begin(); fi!=m.face.end();++fi) - if(!(*fi).IsD()) - if(!Selected || (*fi).IsS()) - { - const ScalarType doubleArea=DoubleArea(*fi); - if((doubleArea<=MinAreaThr) || (doubleArea>=MaxAreaThr) ) - { - Allocator::DeleteFace(m,*fi); - count_fd++; - } - } - return count_fd; - } - - // alias for the old style. Kept for backward compatibility - static int RemoveZeroAreaFace(MeshType& m) { return RemoveFaceOutOfRangeArea(m);} - - // Aliases for the functions that do not look at selection - static int RemoveFaceOutOfRangeArea(MeshType& m, ScalarType MinAreaThr=0, ScalarType MaxAreaThr=(std::numeric_limits::max)()) - { - return RemoveFaceOutOfRangeAreaSel(m,MinAreaThr,MaxAreaThr); - } - - /** - * Is the mesh only composed by quadrilaterals? - */ - static bool IsBitQuadOnly(const MeshType &m) - { - typedef typename MeshType::FaceType F; - if (!m.HasPerFaceFlags()) return false; - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { - unsigned int tmp = fi->Flags()&(F::FAUX0|F::FAUX1|F::FAUX2); - if ( tmp != F::FAUX0 && tmp != F::FAUX1 && tmp != F::FAUX2) return false; - } - return true; - } - - - /** - * Is the mesh only composed by triangles? (non polygonal faces) - */ - static bool IsBitTriOnly(const MeshType &m) - { - if (!m.HasPerFaceFlags()) return true; - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) { - if ( - !fi->IsD() && fi->IsAnyF() - ) return false; - } - return true; - } - - static bool IsBitPolygonal(const MeshType &m){ - return !IsBitTriOnly(m); - } - - /** - * Is the mesh only composed by quadrilaterals and triangles? (no pentas, etc) - */ - static bool IsBitTriQuadOnly(const MeshType &m) - { - typedef typename MeshType::FaceType F; - if (!m.HasPerFaceFlags()) return false; - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { - unsigned int tmp = fi->Flags()&(F::FAUX0|F::FAUX1|F::FAUX2); - if ( tmp!=F::FAUX0 && tmp!=F::FAUX1 && tmp!=F::FAUX2 && tmp!=0 ) return false; - } - return true; - } - - /** - * How many quadrilaterals? - */ - static int CountBitQuads(const MeshType &m) - { - if (!m.HasPerFaceFlags()) return 0; - typedef typename MeshType::FaceType F; - int count=0; - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { - unsigned int tmp = fi->Flags()&(F::FAUX0|F::FAUX1|F::FAUX2); - if ( tmp==F::FAUX0 || tmp==F::FAUX1 || tmp==F::FAUX2) count++; - } - return count / 2; - } - - /** - * How many triangles? (non polygonal faces) - */ - static int CountBitTris(const MeshType &m) - { - if (!m.HasPerFaceFlags()) return m.fn; - int count=0; - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { - if (!(fi->IsAnyF())) count++; - } - return count; - } - - /** - * How many polygons of any kind? (including triangles) - */ - static int CountBitPolygons(const MeshType &m) - { - if (!m.HasPerFaceFlags()) return m.fn; - typedef typename MeshType::FaceType F; - int count = 0; - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { - if (fi->IsF(0)) count++; - if (fi->IsF(1)) count++; - if (fi->IsF(2)) count++; - } - return m.fn - count/2; - } - - /** - * The number of polygonal faces is - * FN - EN_f (each faux edge hides exactly one triangular face or in other words a polygon of n edges has n-3 faux edges.) - * In the general case where a The number of polygonal faces is - * FN - EN_f + VN_f - * where: - * EN_f is the number of faux edges. - * VN_f is the number of faux vertices (e.g vertices completely surrounded by faux edges) - * as a intuitive proof think to a internal vertex that is collapsed onto a border of a polygon: - * it deletes 2 faces, 1 faux edges and 1 vertex so to keep the balance you have to add back the removed vertex. - */ - static int CountBitLargePolygons(MeshType &m) - { - - UpdateFlags::VertexSetV(m); - // First loop Clear all referenced vertices - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if (!fi->IsD()) - for(int i=0;i<3;++i) fi->V(i)->ClearV(); - - - // Second Loop, count (twice) faux edges and mark all vertices touched by non faux edges (e.g vertexes on the boundary of a polygon) - if (!m.HasPerFaceFlags()) return m.fn; - typedef typename MeshType::FaceType F; - int countE = 0; - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if (!fi->IsD()) { - for(int i=0;i<3;++i) - { - if (fi->IsF(i)) - countE++; - else - { - fi->V0(i)->SetV(); - fi->V1(i)->SetV(); - } - } - } - // Third Loop, count the number of referenced vertexes that are completely surrounded by faux edges. - - int countV = 0; - for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if (!vi->IsD() && !vi->IsV()) countV++; - - return m.fn - countE/2 + countV ; - } - - - /** - * Checks that the mesh has consistent per-face faux edges - * (the ones that merges triangles into larger polygons). - * A border edge should never be faux, and faux edges should always be - * reciprocated by another faux edges. - * It requires FF adjacency. - */ - static bool HasConsistentPerFaceFauxFlag(const MeshType &m) - { - assert(m.HasPerFaceFlags()); - assert(m.HasFFTopology()); // todo: remove this constraint - - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - for (int k=0; k<3; k++) - if( fi->IsF(k) != fi->cFFp(k)->IsF(fi->cFFi(k)) ) { - return false; - } - // non-reciprocal faux edge! - // (OR: border faux edge, which is likewise inconsistent) - - return true; - } - - static bool HasConsistentEdges(const MeshType &m) - { - assert(m.HasPerFaceFlags()); - - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - for (int k=0; k<3; k++) - { - VertexType *v0=(*fi).V(0); - VertexType *v1=(*fi).V(1); - VertexType *v2=(*fi).V(2); - if ((v0==v1)||(v0==v2)||(v1==v2)) - return false; - } - - return true; - } - - - - /** - * Count the number of non manifold edges in a mesh, e.g. the edges where there are more than 2 incident faces. - * - * Note that this test is not enough to say that a mesh is two manifold, - * you have to count also the non manifold vertexes. - */ - static int CountNonManifoldEdgeFF( MeshType & m, bool SelectFlag=false) - { - int nmfBit[3]; - nmfBit[0]= FaceType::NewBitFlag(); - nmfBit[1]= FaceType::NewBitFlag(); - nmfBit[2]= FaceType::NewBitFlag(); - - - UpdateFlags::FaceClear(m,nmfBit[0]+nmfBit[1]+nmfBit[2]); - - if(SelectFlag){ - UpdateSelection::ClearVertex(m); - UpdateSelection::ClearFace(m); - } - assert(tri::HasFFAdjacency(m)); - - int edgeCnt = 0; - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - { - if (!fi->IsD()) - { - for(int i=0;i<3;++i) - if(!IsManifold(*fi,i)) - { - if(!(*fi).IsUserBit(nmfBit[i])) - { - ++edgeCnt; - if(SelectFlag) - { - (*fi).V0(i)->SetS(); - (*fi).V1(i)->SetS(); - } - // follow the ring of faces incident on edge i; - face::Pos nmf(&*fi,i); - do - { - if(SelectFlag) nmf.F()->SetS(); - nmf.F()->SetUserBit(nmfBit[nmf.E()]); - nmf.NextF(); - } - while(nmf.f != &*fi); - } - } - } - } - return edgeCnt; - } - - /** Count (and eventually select) non 2-Manifold vertexes of a mesh - * e.g. the vertices with a non 2-manif. neighbourhood but that do not belong to not 2-manif edges. - * typical situation two cones connected by one vertex. - */ - static int CountNonManifoldVertexFF( MeshType & m, bool selectVert = true ) - { - assert(tri::HasFFAdjacency(m)); - if(selectVert) UpdateSelection::ClearVertex(m); - - int nonManifoldCnt=0; - SimpleTempData TD(m.vert,0); - - // First Loop, just count how many faces are incident on a vertex and store it in the TemporaryData Counter. - FaceIterator fi; - for (fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) - { - TD[(*fi).V(0)]++; - TD[(*fi).V(1)]++; - TD[(*fi).V(2)]++; - } - - tri::UpdateFlags::VertexClearV(m); - // Second Loop. - // mark out of the game the vertexes that are incident on non manifold edges. - for (fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) - { - for(int i=0;i<3;++i) - if (!IsManifold(*fi,i)) { - (*fi).V0(i)->SetV(); - (*fi).V1(i)->SetV(); - } - } - // Third Loop, for safe vertexes, check that the number of faces that you can reach starting - // from it and using FF is the same of the previously counted. - for (fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) - { - for(int i=0;i<3;i++) if(!(*fi).V(i)->IsV()){ - (*fi).V(i)->SetV(); - face::Pos pos(&(*fi),i); - - int starSizeFF = pos.NumberOfIncidentFaces(); - - if (starSizeFF != TD[(*fi).V(i)]) - { - if(selectVert) (*fi).V(i)->SetS(); - nonManifoldCnt++; - } - } - } - return nonManifoldCnt; - } - - static void CountEdges( MeshType & m, int &count_e, int &boundary_e ) - { - count_e=0; - boundary_e=0; - UpdateFlags::FaceClearV(m); - FaceIterator fi; - vcg::face::Pos he; - vcg::face::Pos hei; - bool counted =false; - for(fi=m.face.begin();fi!=m.face.end();fi++) - { - if(!((*fi).IsD())) - { - (*fi).SetV(); - count_e +=3; //assume that we have to increase the number of edges with three - for(int j=0; j<3; j++) - { - if (face::IsBorder(*fi,j)) //If this edge is a border edge - boundary_e++; // then increase the number of boundary edges - else if (IsManifold(*fi,j))//If this edge is manifold - { - if((*fi).FFp(j)->IsV()) //If the face on the other side of the edge is already selected - count_e--; // we counted one edge twice - } - else//We have a non-manifold edge - { - hei.Set(&(*fi), j , fi->V(j)); - he=hei; - he.NextF(); - while (he.f!=hei.f)// so we have to iterate all faces that are connected to this edge - { - if (he.f->IsV())// if one of the other faces was already visited than this edge was counted already. - { - counted=true; - break; - } - else - { - he.NextF(); - } - } - if (counted) - { - count_e--; - counted=false; - } - } - } - } - } - } - - - static int CountHoles( MeshType & m) - { - int numholev=0; - FaceIterator fi; - FaceIterator gi; - vcg::face::Pos he; - vcg::face::Pos hei; - - std::vector< std::vector > holes; //indices of vertices - - for(fi=m.face.begin();fi!=m.face.end();++fi) - (*fi).ClearS(); - gi=m.face.begin(); fi=gi; - - for(fi=m.face.begin();fi!=m.face.end();fi++)//for all faces do - { - for(int j=0;j<3;j++)//for all edges - { - if(fi->V(j)->IsS()) continue; - - if(face::IsBorder(*fi,j))//found an unvisited border edge - { - he.Set(&(*fi),j,fi->V(j)); //set the face-face iterator to the current face, edge and vertex - std::vector hole; //start of a new hole - hole.push_back(fi->P(j)); // including the first vertex - numholev++; - he.v->SetS(); //set the current vertex as selected - he.NextB(); //go to the next boundary edge - - - while(fi->V(j) != he.v)//will we do not encounter the first boundary edge. - { - Point3x newpoint = he.v->P(); //select its vertex. - if(he.v->IsS())//check if this vertex was selected already, because then we have an additional hole. - { - //cut and paste the additional hole. - std::vector hole2; - int index = static_cast(find(hole.begin(),hole.end(),newpoint) - - hole.begin()); - for(unsigned int i=index; iSetS(); //set the current vertex as selected - he.NextB(); //go to the next boundary edge - } - holes.push_back(hole); - } - } - } - return static_cast(holes.size()); - } - - /* - Compute the set of connected components of a given mesh - it fills a vector of pair < int , faceptr > with, for each connecteed component its size and a represnant - */ - static int CountConnectedComponents(MeshType &m) - { - std::vector< std::pair > CCV; - return ConnectedComponents(m,CCV); - } - - static int ConnectedComponents(MeshType &m, std::vector< std::pair > &CCV) - { - FaceIterator fi; - FacePointer l; - CCV.clear(); - - for(fi=m.face.begin();fi!=m.face.end();++fi) - (*fi).ClearS(); - - int Compindex=0; - std::stack sf; - FacePointer fpt=&*(m.face.begin()); - for(fi=m.face.begin();fi!=m.face.end();++fi) - { - if(!((*fi).IsD()) && !(*fi).IsS()) - { - (*fi).SetS(); - CCV.push_back(std::make_pair(0,&*fi)); - sf.push(&*fi); - while (!sf.empty()) - { - fpt=sf.top(); - ++CCV.back().first; - sf.pop(); - for(int j=0;j<3;++j) - { - if( !face::IsBorder(*fpt,j) ) - { - l=fpt->FFp(j); - if( !(*l).IsS() ) - { - (*l).SetS(); - sf.push(l); - } - } - } - } - Compindex++; - } - } - assert(int(CCV.size())==Compindex); - return Compindex; - } - - - /** - GENUS. - - A topologically invariant property of a surface defined as - the largest number of non-intersecting simple closed curves that can be - drawn on the surface without separating it. - - Roughly speaking, it is the number of holes in a surface. - The genus g of a closed surface, also called the geometric genus, is related to the - Euler characteristic by the relation $chi$ by $chi==2-2g$. - - The genus of a connected, orientable surface is an integer representing the maximum - number of cuttings along closed simple curves without rendering the resultant - manifold disconnected. It is equal to the number of handles on it. - - For general polyhedra the Euler Formula is: - - V + F - E = 2 - 2G - B - - where V is the number of vertices, F is the number of faces, E is the - number of edges, G is the genus and B is the number of boundary polygons. - - The above formula is valid for a mesh with one single connected component. - By considering multiple connected components the formula becomes: - - V + F - E = 2C - 2Gs - B - - where C is the number of connected components and Gs is the sum of - the genus of all connected components. - - */ - static int MeshGenus(MeshType &m, int numholes, int numcomponents, int count_e) - { - int V = m.vn; - int F = m.fn; - int E = count_e; - return -((V + F - E + numholes - 2 * numcomponents) / 2); - } - - /** - * Check if the given mesh is regular, semi-regular or irregular. - * - * Each vertex of a \em regular mesh has valence 6 except for border vertices - * which have valence 4. - * - * A \em semi-regular mesh is derived from an irregular one applying - * 1-to-4 subdivision recursively. (not checked for now) - * - * All other meshes are \em irregular. - */ - static void IsRegularMesh(MeshType &m, bool &Regular, bool &Semiregular) - { - // This algorithm requires Vertex-Face topology - assert(m.HasVFTopology()); - - Regular = true; - - VertexIterator vi; - - // for each vertex the number of edges are count - for (vi = m.vert.begin(); vi != m.vert.end(); ++vi) - { - if (!vi->IsD()) - { - face::Pos he((*vi).VFp(), &*vi); - face::Pos ht = he; - - int n=0; - bool border=false; - do - { - ++n; - ht.NextE(); - if (ht.IsBorder()) - border=true; - } - while (ht != he); - - if (border) - n = n/2; - - if ((n != 6)&&(!border && n != 4)) - { - Regular = false; - break; - } - } - } - - if (!Regular) - Semiregular = false; - else - { - // For now we do not account for semi-regularity - Semiregular = false; - } - } - - static void IsOrientedMesh(MeshType &m, bool &Oriented, bool &Orientable) - { - assert(&Oriented != &Orientable); - // This algorithms requires FF topology - assert(m.HasFFTopology()); - - Orientable = true; - Oriented = true; - - // Ensure that each face is deselected - FaceIterator fi; - for (fi = m.face.begin(); fi != m.face.end(); ++fi) - fi->ClearS(); - - // initialize stack - std::stack faces; - - // for each face of the mesh - FacePointer fp,fpaux; - int iaux; - for (fi = m.face.begin(); fi != m.face.end(); ++fi) - { - if (!fi->IsD() && !fi->IsS()) - { - // each face put in the stack is selected (and oriented) - fi->SetS(); - faces.push(&(*fi)); - - // empty the stack - while (!faces.empty()) - { - fp = faces.top(); - faces.pop(); - - // make consistently oriented the adjacent faces - for (int j = 0; j < 3; j++) - { - // get one of the adjacent face - fpaux = fp->FFp(j); - iaux = fp->FFi(j); - - if (!fpaux->IsD() && fpaux != fp && face::IsManifold(*fp, j)) - { - if (!CheckOrientation(*fpaux, iaux)) - { - Oriented = false; - - if (!fpaux->IsS()) - { - face::SwapEdge(*fpaux, iaux); - assert(CheckOrientation(*fpaux, iaux)); - } - else - { - Orientable = false; - break; - } - } - - // put the oriented face into the stack - - if (!fpaux->IsS()) - { - fpaux->SetS(); - faces.push(fpaux); - } - } - } - } - } - - if (!Orientable) break; - } - } - /// Flip the orientation of the whole mesh flipping all the faces (by swapping the first two vertices) - static void FlipMesh(MeshType &m, bool selected=false) - { - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if(!(*fi).IsD()) - if(!selected || (*fi).IsS()) - { - face::SwapEdge((*fi), 0); - if (HasPerWedgeTexCoord(m)) - std::swap((*fi).WT(0),(*fi).WT(1)); - } - } - // Search and remove small single triangle folds - // - a face has normal opposite to all other faces - // - choose the edge that brings to the face f1 containing the vertex opposite to that edge. - static int RemoveFaceFoldByFlip(MeshType &m, float normalThresholdDeg=175, bool repeat=true) - { - assert(m.HasFFTopology()); - assert(m.HasPerVertexMark()); - //Counters for logging and convergence - int count, total = 0; - - do { - tri::UpdateTopology::FaceFace(m); - tri::UnMarkAll(m); - count = 0; - - ScalarType NormalThrRad = math::ToRad(normalThresholdDeg); - ScalarType eps = 0.0001; // this epsilon value is in absolute value. It is a distance from edge in baricentric coords. - //detection stage - for(FaceIterator fi=m.face.begin();fi!= m.face.end();++fi ) if(!(*fi).IsV()) - { Point3 NN = vcg::NormalizedNormal((*fi)); - if( vcg::Angle(NN,vcg::NormalizedNormal(*(*fi).FFp(0))) > NormalThrRad && - vcg::Angle(NN,vcg::NormalizedNormal(*(*fi).FFp(1))) > NormalThrRad && - vcg::Angle(NN,vcg::NormalizedNormal(*(*fi).FFp(2))) > NormalThrRad ) - { - (*fi).SetS(); - //(*fi).C()=Color4b(Color4b::Red); - // now search the best edge to flip - for(int i=0;i<3;i++) - { - Point3 &p=(*fi).P2(i); - Point3 L; - bool ret = vcg::InterpolationParameters((*(*fi).FFp(i)),vcg::Normal(*(*fi).FFp(i)),p,L); - if(ret && L[0]>eps && L[1]>eps && L[2]>eps) - { - (*fi).FFp(i)->SetS(); - (*fi).FFp(i)->SetV(); - //(*fi).FFp(i)->C()=Color4b(Color4b::Green); - if(face::CheckFlipEdge( *fi, i )) { - face::FlipEdge( *fi, i ); - ++count; ++total; - } - } - } - } - } - - // tri::UpdateNormals::PerFace(m); - } - while( repeat && count ); - return total; - } - - - static int RemoveTVertexByFlip(MeshType &m, float threshold=40, bool repeat=true) - { - assert(m.HasFFTopology()); - assert(m.HasPerVertexMark()); - //Counters for logging and convergence - int count, total = 0; - - do { - tri::UpdateTopology::FaceFace(m); - tri::UnMarkAll(m); - count = 0; - - //detection stage - for(unsigned int index = 0 ; index < m.face.size(); ++index ) - { - FacePointer f = &(m.face[index]); float sides[3]; Point3 dummy; - sides[0] = Distance(f->P(0), f->P(1)); - sides[1] = Distance(f->P(1), f->P(2)); - sides[2] = Distance(f->P(2), f->P(0)); - // Find largest triangle side - int i = std::find(sides, sides+3, std::max( std::max(sides[0],sides[1]), sides[2])) - (sides); - if( tri::IsMarked(m,f->V2(i) )) continue; - - if( PSDist(f->P2(i),f->P(i),f->P1(i),dummy)*threshold <= sides[i] ) - { - tri::Mark(m,f->V2(i)); - if(face::CheckFlipEdge( *f, i )) { - // Check if EdgeFlipping improves quality - FacePointer g = f->FFp(i); int k = f->FFi(i); - Triangle3 t1(f->P(i), f->P1(i), f->P2(i)), t2(g->P(k), g->P1(k), g->P2(k)), - t3(f->P(i), g->P2(k), f->P2(i)), t4(g->P(k), f->P2(i), g->P2(k)); - - if ( std::min( t1.QualityFace(), t2.QualityFace() ) < std::min( t3.QualityFace(), t4.QualityFace() )) - { - face::FlipEdge( *f, i ); - ++count; ++total; - } - } - - } - } - - // tri::UpdateNormals::PerFace(m); - } - while( repeat && count ); - return total; - } - - static int RemoveTVertexByCollapse(MeshType &m, float threshold=40, bool repeat=true) - { - assert(tri::HasPerVertexMark(m)); - //Counters for logging and convergence - int count, total = 0; - - do { - tri::UnMarkAll(m); - count = 0; - - //detection stage - for(unsigned int index = 0 ; index < m.face.size(); ++index ) - { - FacePointer f = &(m.face[index]); float sides[3]; Point3 dummy; - sides[0] = Distance(f->P(0), f->P(1)); sides[1] = Distance(f->P(1), f->P(2)); sides[2] = Distance(f->P(2), f->P(0)); - int i = std::find(sides, sides+3, std::max( std::max(sides[0],sides[1]), sides[2])) - (sides); - if( tri::IsMarked(m,f->V2(i) )) continue; - - if( PSDist(f->P2(i),f->P(i),f->P1(i),dummy)*threshold <= sides[i] ) - { - tri::Mark(m,f->V2(i)); - - int j = Distance(dummy,f->P(i))P1(i))?i:(i+1)%3; - f->P2(i) = f->P(j); tri::Mark(m,f->V(j)); - ++count; ++total; - } - } - - - tri::Clean::RemoveDuplicateVertex(m); - tri::Allocator::CompactFaceVector(m); - tri::Allocator::CompactVertexVector(m); - } - while( repeat && count ); - - return total; - } - - static bool SelfIntersections(MeshType &m, std::vector &ret) - { - assert(HasPerFaceMark(m));// Needed by the UG - Box3< ScalarType> bbox; - TriMeshGrid gM; - ret.clear(); - FaceIterator fi; - int referredBit = FaceType::NewBitFlag(); - tri::UpdateFlags::FaceClear(m,referredBit); - - std::vector inBox; - gM.Set(m.face.begin(),m.face.end()); - - for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) - { - (*fi).SetUserBit(referredBit); - (*fi).GetBBox(bbox); - vcg::tri::GetInBoxFace(m, gM, bbox,inBox); - bool Intersected=false; - typename std::vector::iterator fib; - for(fib=inBox.begin();fib!=inBox.end();++fib) - { - if(!(*fib)->IsUserBit(referredBit) && (*fib != &*fi) ) - if(TestIntersection(&*fi,*fib)){ - ret.push_back(*fib); - if(!Intersected) { - ret.push_back(&*fi); - Intersected=true; - } - } - } - inBox.clear(); - } - - FaceType::DeleteBitFlag(referredBit); - return (ret.size()>0); - } - - /** - This function simply test that the vn and fn counters be consistent with the size of the containers and the number of deleted simplexes. - */ - static bool IsSizeConsistent(MeshType &m) - { - int DeletedVertexNum=0; - for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if((*vi).IsD()) DeletedVertexNum++; - - int DeletedFaceNum=0; - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if((*fi).IsD()) DeletedFaceNum++; - - if(size_t(m.vn+DeletedVertexNum) != m.vert.size()) return false; - if(size_t(m.fn+DeletedFaceNum) != m.face.size()) return false; - - return true; - } - - /** - This function simply test that all the faces have a consistent face-face topology relation. - useful for checking that a topology modifying algorithm does not mess something. - */ - static bool IsFFAdjacencyConsistent(MeshType &m) - { - if(!HasFFAdjacency(m)) return false; - - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - { - for(int i=0;i<3;++i) - if(!FFCorrectness(*fi, i)) return false; - } - return true; - } - -/** - This function simply test that a mesh has some reasonable tex coord. - */ - static bool HasConsistentPerWedgeTexCoord(MeshType &m) - { - if(!HasPerWedgeTexCoord(m)) return false; - - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - { FaceType &f=(*fi); - if( ! ( (f.WT(0).N() == f.WT(1).N()) && (f.WT(0).N() == (*fi).WT(2).N()) ) ) - return false; // all the vertices must have the same index. - - if((*fi).WT(0).N() <0) return false; // no undefined texture should be allowed - } - return true; - } - - /** - Simple check that there are no face with all collapsed tex coords. - */ - static bool HasZeroTexCoordFace(MeshType &m) - { - if(!HasPerWedgeTexCoord(m)) return false; - - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - { - if( (*fi).WT(0).P() == (*fi).WT(1).P() && (*fi).WT(0).P() == (*fi).WT(2).P() ) return false; - } - return true; - } - - - /** - This function test if two face intersect. - We assume that the two faces are different. - if the faces share an edge no test is done. - if the faces share only a vertex, the opposite edge is tested against the face - */ - static bool TestIntersection(FaceType *f0,FaceType *f1) - { - assert(f0!=f1); - int sv = face::CountSharedVertex(f0,f1); - if(sv==0) return (vcg::IntersectionTriangleTriangle((*f0),(*f1))); - // if the faces share only a vertex, the opposite edge is tested against the face - if(sv==1) - { - int i0,i1; ScalarType a,b; - face::SharedVertex(f0,f1,i0,i1); - if(vcg::IntersectionSegmentTriangle(Segment3((*f0).V1(i0)->P(),(*f0).V2(i0)->P()), *f1, a, b) ) return true; - if(vcg::IntersectionSegmentTriangle(Segment3((*f1).V1(i1)->P(),(*f1).V2(i1)->P()), *f0, a, b) ) return true; - } - return false; - } - - - -/** - This function merge all the vertices that are closer than the given radius -*/ -static int MergeCloseVertex(MeshType &m, const ScalarType radius) - { - int mergedCnt=0; - mergedCnt = ClusterVertex(m,radius); - RemoveDuplicateVertex(m,true); - return mergedCnt; - } - -static int ClusterVertex(MeshType &m, const ScalarType radius) - { - typedef vcg::SpatialHashTable SampleSHT; - SampleSHT sht; - tri::VertTmark markerFunctor; - typedef vcg::vertex::PointDistanceFunctor VDistFunct; - std::vector closests; - int mergedCnt=0; - Point3f closestPt; - sht.Set(m.vert.begin(), m.vert.end()); - UpdateFlags::VertexClearV(m); - for(VertexIterator viv = m.vert.begin(); viv!= m.vert.end(); ++viv) - if(!(*viv).IsD() && !(*viv).IsV()) - { - (*viv).SetV(); - Point3f p = viv->cP(); - Box3f bb(p-Point3f(radius,radius,radius),p+Point3f(radius,radius,radius)); - GridGetInBox(sht, markerFunctor, bb, closests); - // qDebug("Vertex %i has %i closest", &*viv - &*m.vert.begin(),closests.size()); - for(size_t i=0; icP()); - if(dist < radius && !closests[i]->IsV()) - { - printf("%f %f \n",dist,radius); - mergedCnt++; - closests[i]->SetV(); - closests[i]->P()=p; - } - } - } - return mergedCnt; - } - - -static std::pair RemoveSmallConnectedComponentsSize(MeshType &m, int maxCCSize) -{ - std::vector< std::pair > CCV; - int TotalCC=ConnectedComponents(m, CCV); - int DeletedCC=0; - - ConnectedIterator ci; - for(unsigned int i=0;i FPV; - if(CCV[i].first::iterator fpvi; - for(fpvi=FPV.begin(); fpvi!=FPV.end(); ++fpvi) - Allocator::DeleteFace(m,(**fpvi)); - } - } - return std::make_pair(TotalCC,DeletedCC); -} - -/// Remove the connected components smaller than a given diameter -// it returns a pair with the number of connected components and the number of deleted ones. -static std::pair RemoveSmallConnectedComponentsDiameter(MeshType &m, ScalarType maxDiameter) -{ - std::vector< std::pair > CCV; - int TotalCC=ConnectedComponents(m, CCV); - int DeletedCC=0; - tri::ConnectedIterator ci; - for(unsigned int i=0;i FPV; - for(ci.start(m,CCV[i].second);!ci.completed();++ci) - { - FPV.push_back(*ci); - bb.Add((*ci)->P(0)); - bb.Add((*ci)->P(1)); - bb.Add((*ci)->P(2)); - } - if(bb.Diag()::iterator fpvi; - for(fpvi=FPV.begin(); fpvi!=FPV.end(); ++fpvi) - tri::Allocator::DeleteFace(m,(**fpvi)); - } - } - return std::make_pair(TotalCC,DeletedCC); -} - - }; // end class - /*@}*/ - - } //End Namespace Tri -} // End Namespace vcg -#endif diff --git a/vcg/complex/trimesh/clip.h b/vcg/complex/trimesh/clip.h deleted file mode 100644 index ef3f2347..00000000 --- a/vcg/complex/trimesh/clip.h +++ /dev/null @@ -1,1114 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ - -/**************************************************************************** - History - -$Log: not supported by cvs2svn $ - -****************************************************************************/ - -#ifndef __VCGLIB_TRI_CLIP -#define __VCGLIB_TRI_CLIP - -#include - -#ifdef _WIN32 - #ifndef __MINGW32__ - #include - #define STDEXT stdext - #else - #include - #define STDEXT __gnu_cxx - #endif -#else - #include - #define STDEXT __gnu_cxx -#endif -namespace vcg -{ -namespace tri -{ - - template - class GenericVertexInterpolator - { - public: - typedef typename MESH_TYPE::VertexType VertexType; - typedef GenericVertexInterpolator ClassType; - typedef typename VertexType::CoordType CoordType; - typedef typename CoordType::ScalarType ScalarType; - GenericVertexInterpolator(MESH_TYPE &_m) : m(_m) {} - private: - MESH_TYPE &m; - public: - inline void operator () (const VertexType & v0, const VertexType & v1, const VertexType & v2, const ScalarType & a, const ScalarType & b, VertexType & r) const - { - // position - r.P() = v0.P() + (v1.P() - v0.P()) * a + (v2.P() - v0.P()) * b; - - // normal - if (tri::HasPerVertexNormal(m)) - { - r.N() = v0.cN() + (v1.cN() - v0.cN()) * a + (v2.cN() - v0.cN()) * b; - } - - // color - if (tri::HasPerVertexColor(m)) - { - vcg::Point4 vc[3]; - vc[0].Import(v0.cC()); - vc[1].Import(v1.cC()); - vc[2].Import(v2.cC()); - const vcg::Point4 rc = (vc[0] + (vc[1] - vc[0]) * a + (vc[2] - vc[0]) * b); - r.C()[0] = (typename vcg::Color4b::ScalarType)(rc[0]); - r.C()[1] = (typename vcg::Color4b::ScalarType)(rc[1]); - r.C()[2] = (typename vcg::Color4b::ScalarType)(rc[2]); - r.C()[3] = (typename vcg::Color4b::ScalarType)(rc[3]); - } - - // texcoord - if (tri::HasPerVertexTexCoord(m)) - { - const short nt = 1; //typename VertexType::TextureType::N(); - for (short i=0; i -class TriMeshClipper -{ -public: - - typedef TriMeshClipper ClassType; - typedef TRIMESHTYPE TriMeshType; - typedef typename TriMeshType::FaceType FaceType; - typedef typename FaceType::VertexType VertexType; - typedef typename VertexType::CoordType CoordType; - typedef typename CoordType::ScalarType ScalarType; - - /* - static inline void Box(const Box3 & b, VERTEXINTEPOLATOR & vInterp, TriMeshType & m); - - Clip mesh "m" against an axis aligned box (in place version); - - Notes: - 1) faces marked as deleted are skipped; - 2) faces completely outside box are marked as deleted; - 3) faces completely inside box are left unchanged; - 4) faces intersecting box's sides are marked as deleted: - they are replaced with proper tesselation; new vertices and faces - are created, so reallocation could occour; previously saved pointers - could not to be valid anymore, thus they should be updated; - 5) vInterp functor must implement a n operator with signature - void operator () (const VERTEX & v0, const VERTEX & v1, const VERTEX & v2, const Scalar & a, const Scalar & b, VERTEX & r); - its semantic is to intepolate vertex attribute across triangle; a typical implementation is; - r.P() = v0.P() + a * (v1.P() - v0.P()) + b * (v2.P() - v0.P()); // interpolate position - r.N() = v0.N() + a * (v1.N() - v0.N()) + b * (v2.N() - v0.N()); // interpolate normal - ... // interpolate other vertex attributes - */ - template - class VertexClipInfo - { - public: -// typedef VertexClipInfo ClassType; - - ScalarType fU; - ScalarType fV; - unsigned int idx; - unsigned int tref; - }; - typedef typename std::vector< VertexClipInfo > VertexClipInfoVec; - class TriangleInfo - { - public: - typedef TriangleInfo ClassType; - - unsigned int v[3]; - unsigned int idx; - }; - - typedef std::vector TriangleInfoVec; - - class EdgeIsect - { - public: - CoordType p; - unsigned int idx; - }; - - template - static inline void Box(const Box3 & b, VERTEXINTEPOLATOR & vInterp, TriMeshType & m) - { - std::vector facesToDelete; - ClassType::Box(b, vInterp, m, facesToDelete); - for (size_t i=0; in = 0; - } - }; - - typedef STDEXT::hash_map UIntHMap; - typedef typename UIntHMap::iterator UIntHMap_i; - typedef typename UIntHMap::value_type UIntHMap_v; - - typedef STDEXT::hash_map EdgeMap; - typedef typename EdgeMap::iterator EdgeMap_i; - typedef typename EdgeMap::value_type EdgeMap_v; - - typedef typename TriMeshType::FaceIterator FaceIterator; - - template - static inline void Box(const Box3 & b, VERTEXINTEPOLATOR & vInterp, TriMeshType & m, FACEINDEXCONTAINER & facesToDelete) - { - if (m.fn <= 0) - { - return; - } - - EdgeMap edges; - VertexClipInfoVec vInfos; - TriangleInfoVec tInfos; - - CoordType vTriangle[4]; - CoordType vClipped[64]; - - CoordType pvP0[64]; - CoordType pvP1[64]; - - unsigned int numDeletedTris = 0; - unsigned int numTriangles = 0; - unsigned int numVertices = 0; - - unsigned int vIdx = (unsigned int)(m.vn); - unsigned int tIdx = (unsigned int)(m.fn); - - ScalarType boxOffsets[6]; - - boxOffsets[0] = b.min[0]; - boxOffsets[1] = -b.max[0]; - boxOffsets[2] = b.min[1]; - boxOffsets[3] = -b.max[1]; - boxOffsets[4] = b.min[2]; - boxOffsets[5] = -b.max[2]; - - UIntHMap emptyMap; - EdgeIntersections emptyIsects; - - const ScalarType eps = (ScalarType)(1e-6); - - for (FaceIterator it=m.face.begin(); it!=m.face.end(); ++it) - { - if ((*it).IsD()) - { - continue; - } - - unsigned int cc[3]; - - cc[0] = ClassType::BoxClipCode(boxOffsets, (*it).V(0)->P()); - cc[1] = ClassType::BoxClipCode(boxOffsets, (*it).V(1)->P()); - cc[2] = ClassType::BoxClipCode(boxOffsets, (*it).V(2)->P()); - - if ((cc[0] | cc[1] | cc[2]) == 0) - { - continue; - } - - const unsigned int refT = (unsigned int)(std::distance(m.face.begin(), it)); - - if ((cc[0] & cc[1] & cc[2]) != 0) - { - facesToDelete.push_back(refT); - (*it).SetD(); - numDeletedTris++; - continue; - } - - facesToDelete.push_back(refT); - - vTriangle[0] = (*it).V(0)->P(); - vTriangle[1] = (*it).V(1)->P(); - vTriangle[2] = (*it).V(2)->P(); - vTriangle[3] = (*it).V(0)->P(); - - unsigned int n, n0, n1; - - ClipPolygonLine(0, b.min[0], vTriangle, 4, pvP1, n1); - ClipPolygonLine(1, b.max[0], pvP1, n1, pvP0, n0); - - ClipPolygonLine(2, b.min[1], pvP0, n0, pvP1, n1); - ClipPolygonLine(3, b.max[1], pvP1, n1, pvP0, n0); - - ClipPolygonLine(4, b.min[2], pvP0, n0, pvP1, n1); - ClipPolygonLine(5, b.max[2], pvP1, n1, vClipped, n); - - assert(n < 64); - - unsigned int firstV, lastV; - - if (n > 2) - { - if (vClipped[0] == vClipped[n - 1]) - { - n--; - } - - const CoordType vU = vTriangle[1] - vTriangle[0]; - const CoordType vV = vTriangle[2] - vTriangle[0]; - - const ScalarType tArea = (vU ^ vV).SquaredNorm(); - if (tArea < eps) - { - continue; - } - - unsigned int tvidx[3]; - tvidx[0] = (*it).V(0) - &(*(m.vert.begin())); - tvidx[1] = (*it).V(1) - &(*(m.vert.begin())); - tvidx[2] = (*it).V(2) - &(*(m.vert.begin())); - - numTriangles += n - 2; - -// size_t vBegin = vInfos.size(); - - VertexClipInfo vnfo; - TriangleInfo tnfo; - - unsigned int vmin[3]; - unsigned int vmax[3]; - - if (tvidx[0] < tvidx[1]) - { - vmin[0] = tvidx[0]; - vmax[0] = tvidx[1]; - } - else - { - vmin[0] = tvidx[1]; - vmax[0] = tvidx[0]; - } - - if (tvidx[0] < tvidx[2]) - { - vmin[1] = tvidx[0]; - vmax[1] = tvidx[2]; - } - else - { - vmin[1] = tvidx[2]; - vmax[1] = tvidx[0]; - } - - if (tvidx[1] < tvidx[2]) - { - vmin[2] = tvidx[1]; - vmax[2] = tvidx[2]; - } - else - { - vmin[2] = tvidx[2]; - vmax[2] = tvidx[1]; - } - - for (unsigned int i=0; i mi = edges.insert(std::make_pair(vmin[1], emptyMap)); - std::pair hi = (*(mi.first)).second.insert(std::make_pair(vmax[1], emptyIsects)); - bool found = false; - for (unsigned int s=0; s<(*(hi.first)).second.n; ++s) - { - if (vClipped[i] == (*(hi.first)).second.isects[s].p) - { - found = true; - vnfo.idx = (*(hi.first)).second.isects[s].idx; - break; - } - } - if (!found) - { - vnfo.idx = vIdx++; - numVertices++; - vInfos.push_back(vnfo); - - (*(hi.first)).second.isects[(*(hi.first)).second.n].p = vClipped[i]; - (*(hi.first)).second.isects[(*(hi.first)).second.n].idx = vnfo.idx; - (*(hi.first)).second.n++; - } - } - else if (vnfo.fU < eps) - { - std::pair mi = edges.insert(std::make_pair(vmin[0], emptyMap)); - std::pair hi = (*(mi.first)).second.insert(std::make_pair(vmax[0], emptyIsects)); - bool found = false; - for (unsigned int s=0; s<(*(hi.first)).second.n; ++s) - { - if (vClipped[i] == (*(hi.first)).second.isects[s].p) - { - found = true; - vnfo.idx = (*(hi.first)).second.isects[s].idx; - break; - } - } - if (!found) - { - vnfo.idx = vIdx++; - numVertices++; - vInfos.push_back(vnfo); - - (*(hi.first)).second.isects[(*(hi.first)).second.n].p = vClipped[i]; - (*(hi.first)).second.isects[(*(hi.first)).second.n].idx = vnfo.idx; - (*(hi.first)).second.n++; - } - } - else if ((vnfo.fU + vnfo.fV) >= ((ScalarType)(1.0 - 1e-5))) - { - std::pair mi = edges.insert(std::make_pair(vmin[2], emptyMap)); - std::pair hi = (*(mi.first)).second.insert(std::make_pair(vmax[2], emptyIsects)); - bool found = false; - for (unsigned int s=0; s<(*(hi.first)).second.n; ++s) - { - if (vClipped[i] == (*(hi.first)).second.isects[s].p) - { - found = true; - vnfo.idx = (*(hi.first)).second.isects[s].idx; - break; - } - } - if (!found) - { - vnfo.idx = vIdx++; - numVertices++; - vInfos.push_back(vnfo); - - (*(hi.first)).second.isects[(*(hi.first)).second.n].p = vClipped[i]; - (*(hi.first)).second.isects[(*(hi.first)).second.n].idx = vnfo.idx; - (*(hi.first)).second.n++; - } - } - else - { - vnfo.idx = vIdx++; - numVertices++; - vInfos.push_back(vnfo); - } - - if (i == 0) - { - firstV = vnfo.idx; - } - - if (i > 1) - { - tnfo.idx = tIdx++; - tnfo.v[0] = firstV; - tnfo.v[1] = lastV; - tnfo.v[2] = vnfo.idx; - - tInfos.push_back(tnfo); - } - - lastV = vnfo.idx; - } - } - } - - if (numTriangles == 0) - { - return; - } - - const unsigned int vSize = (unsigned int)(m.vn); - const unsigned int tSize = (unsigned int)(m.fn); - - typedef Allocator TriMeshAllocatorType; - - TriMeshAllocatorType::AddVertices(m, numVertices); - TriMeshAllocatorType::AddFaces(m, numTriangles); - - unsigned int j = vSize; - for (size_t i=0; i= vSize) - { - const unsigned int tref = vInfos[i].tref; - vInterp(*(m.face[tref].V(0)), *(m.face[tref].V(1)), *(m.face[tref].V(2)), vInfos[i].fV, vInfos[i].fU, m.vert[j]); - j++; - } - } - - j = tSize; - for (size_t i=0; i & b, VERTEXINTEPOLATOR & vInterp, const TriMeshType & m, TriMeshType & r); - - Clip mesh "m" against an axis aligned box and put resulting data in mesh "r" (out of place version); - - Notes: - 1) input mesh is not modified; - 2) faces marked as deleted are skipped; - 3) vInterp functor must implement a n operator with signature - void operator () (const VERTEX & v0, const VERTEX & v1, const VERTEX & v2, const Scalar & a, const Scalar & b, VERTEX & r); - its semantic is to intepolate vertex attribute across triangle; a typical implementation is; - r.P() = v0.P() + a * (v1.P() - v0.P()) + b * (v2.P() - v0.P()); // interpolate position - r.N() = v0.N() + a * (v1.N() - v0.N()) + b * (v2.N() - v0.N()); // interpolate normal - ... // interpolate other vertex attributes - */ - - template - static inline void Box(const Box3 & b, VERTEXINTEPOLATOR & vInterp, const TriMeshType & m, TriMeshType & r) - { - r.Clear(); - - if (m.fn <= 0) - { - return; - } - - class VertexClipInfo - { - public: - typedef VertexClipInfo ClassType; - - ScalarType fU; - ScalarType fV; - unsigned int idx; - unsigned int tref; - }; - - typedef std::vector VertexClipInfoVec; - - class TriangleInfo - { - public: - typedef TriangleInfo ClassType; - - unsigned int v[3]; - unsigned int idx; - }; - - typedef std::vector TriangleInfoVec; - - class EdgeIsect - { - public: - CoordType p; - unsigned int idx; - }; - - class EdgeIntersections - { - public: - unsigned int n; - EdgeIsect isects[6]; - - EdgeIntersections(void) - { - this->n = 0; - } - }; - - typedef STDEXT::hash_map UIntHMap; - typedef typename UIntHMap::iterator UIntHMap_i; - typedef typename UIntHMap::value_type UIntHMap_v; - - typedef STDEXT::hash_map EdgeMap; - typedef typename EdgeMap::iterator EdgeMap_i; - typedef typename EdgeMap::value_type EdgeMap_v; - - typedef STDEXT::hash_map UIHMap; - typedef typename UIHMap::iterator UIHMap_i; - - typedef typename TriMeshType::ConstFaceIterator ConstFaceIterator; - - UIHMap origVertsMap; - EdgeMap edges; - VertexClipInfoVec vInfos; - TriangleInfoVec tInfos; - - CoordType vTriangle[4]; - CoordType vClipped[64]; - - CoordType pvP0[64]; - CoordType pvP1[64]; - - unsigned int numDeletedTris = 0; - unsigned int numTriangles = 0; - unsigned int numVertices = 0; - - unsigned int vIdx = 0; - unsigned int tIdx = 0; - - ScalarType boxOffsets[6]; - - boxOffsets[0] = b.min[0]; - boxOffsets[1] = -b.max[0]; - boxOffsets[2] = b.min[1]; - boxOffsets[3] = -b.max[1]; - boxOffsets[4] = b.min[2]; - boxOffsets[5] = -b.max[2]; - - UIntHMap emptyMap; - EdgeIntersections emptyIsects; - - const ScalarType eps = (ScalarType)(1e-6); - - for (ConstFaceIterator it=m.face.begin(); it!=m.face.end(); ++it) - { - if ((*it).IsD()) - { - continue; - } - - unsigned int cc[3]; - - cc[0] = ClassType::BoxClipCode(boxOffsets, (*it).V(0)->P()); - cc[1] = ClassType::BoxClipCode(boxOffsets, (*it).V(1)->P()); - cc[2] = ClassType::BoxClipCode(boxOffsets, (*it).V(2)->P()); - - if ((cc[0] | cc[1] | cc[2]) == 0) - { - TriangleInfo tnfo; - VertexClipInfo vnfo; - - tnfo.idx = tIdx++; - - for (int i=0; i<3; ++i) - { - const unsigned int v = (*it).V(i) - &(*(m.vert.begin())); - std::pair hi = origVertsMap.insert(std::make_pair(v, vIdx)); - - if (hi.second) - { - vnfo.idx = v; - vInfos.push_back(vnfo); - tnfo.v[i] = vIdx++; - } - else - { - tnfo.v[i] = (*(hi.first)).second; - } - } - - tInfos.push_back(tnfo); - - continue; - } - - if ((cc[0] & cc[1] & cc[2]) != 0) - { - numDeletedTris++; - continue; - } - - vTriangle[0] = (*it).V(0)->P(); - vTriangle[1] = (*it).V(1)->P(); - vTriangle[2] = (*it).V(2)->P(); - vTriangle[3] = (*it).V(0)->P(); - - unsigned int n, n0, n1; - - ClipPolygonLine(0, b.min[0], vTriangle, 4, pvP1, n1); - ClipPolygonLine(1, b.max[0], pvP1, n1, pvP0, n0); - - ClipPolygonLine(2, b.min[1], pvP0, n0, pvP1, n1); - ClipPolygonLine(3, b.max[1], pvP1, n1, pvP0, n0); - - ClipPolygonLine(4, b.min[2], pvP0, n0, pvP1, n1); - ClipPolygonLine(5, b.max[2], pvP1, n1, vClipped, n); - - assert(n < 64); - - unsigned int firstV, lastV; - - - if (n > 2) - { - if (vClipped[0] == vClipped[n - 1]) - { - n--; - } - - const CoordType vU = vTriangle[1] - vTriangle[0]; - const CoordType vV = vTriangle[2] - vTriangle[0]; - - const ScalarType tArea = (vU ^ vV).SquaredNorm(); - if (tArea < eps) - { - continue; - } - - unsigned int tvidx[3]; - tvidx[0] = (*it).V(0) - &(*(m.vert.begin())); - tvidx[1] = (*it).V(1) - &(*(m.vert.begin())); - tvidx[2] = (*it).V(2) - &(*(m.vert.begin())); - - unsigned int refT = (unsigned int)(std::distance(m.face.begin(), it)); - - numTriangles += n - 2; - - size_t vBegin = vInfos.size(); - - VertexClipInfo vnfo; - TriangleInfo tnfo; - - unsigned int vmin[3]; - unsigned int vmax[3]; - - if (tvidx[0] < tvidx[1]) - { - vmin[0] = tvidx[0]; - vmax[0] = tvidx[1]; - } - else - { - vmin[0] = tvidx[1]; - vmax[0] = tvidx[0]; - } - - if (tvidx[0] < tvidx[2]) - { - vmin[1] = tvidx[0]; - vmax[1] = tvidx[2]; - } - else - { - vmin[1] = tvidx[2]; - vmax[1] = tvidx[0]; - } - - if (tvidx[1] < tvidx[2]) - { - vmin[2] = tvidx[1]; - vmax[2] = tvidx[2]; - } - else - { - vmin[2] = tvidx[2]; - vmax[2] = tvidx[1]; - } - - for (unsigned int i=0; i hi = origVertsMap.insert(std::make_pair(tvidx[0], vIdx)); - if (hi.second) - { - vnfo.idx = tvidx[0]; - vInfos.push_back(vnfo); - currVIdx = vIdx++; - } - else - { - currVIdx = (*(hi.first)).second; - } - } - else if (vClipped[i] == vTriangle[1]) - { - std::pair hi = origVertsMap.insert(std::make_pair(tvidx[1], vIdx)); - if (hi.second) - { - vnfo.idx = tvidx[1]; - vInfos.push_back(vnfo); - currVIdx = vIdx++; - } - else - { - currVIdx = (*(hi.first)).second; - } - } - else if (vClipped[i] == vTriangle[2]) - { - std::pair hi = origVertsMap.insert(std::make_pair(tvidx[2], vIdx)); - if (hi.second) - { - vnfo.idx = tvidx[2]; - vInfos.push_back(vnfo); - currVIdx = vIdx++; - } - else - { - currVIdx = (*(hi.first)).second; - } - } - else if (vnfo.fV < eps) - { - std::pair mi = edges.insert(std::make_pair(vmin[1], emptyMap)); - std::pair hi = (*(mi.first)).second.insert(std::make_pair(vmax[1], emptyIsects)); - bool found = false; - for (unsigned int s=0; s<(*(hi.first)).second.n; ++s) - { - if (vClipped[i] == (*(hi.first)).second.isects[s].p) - { - found = true; - vnfo.idx = (unsigned int)(-1); - currVIdx = (*(hi.first)).second.isects[s].idx; - break; - } - } - if (!found) - { - (*(hi.first)).second.isects[(*(hi.first)).second.n].p = vClipped[i]; - (*(hi.first)).second.isects[(*(hi.first)).second.n].idx = vIdx; - (*(hi.first)).second.n++; - - vnfo.idx = (unsigned int)(-1); - numVertices++; - vInfos.push_back(vnfo); - currVIdx = vIdx++; - } - } - else if (vnfo.fU < eps) - { - std::pair mi = edges.insert(std::make_pair(vmin[0], emptyMap)); - std::pair hi = (*(mi.first)).second.insert(std::make_pair(vmax[0], emptyIsects)); - bool found = false; - for (unsigned int s=0; s<(*(hi.first)).second.n; ++s) - { - if (vClipped[i] == (*(hi.first)).second.isects[s].p) - { - found = true; - vnfo.idx = (unsigned int)(-1); - currVIdx = (*(hi.first)).second.isects[s].idx; - break; - } - } - if (!found) - { - (*(hi.first)).second.isects[(*(hi.first)).second.n].p = vClipped[i]; - (*(hi.first)).second.isects[(*(hi.first)).second.n].idx = vIdx; - (*(hi.first)).second.n++; - - vnfo.idx = (unsigned int)(-1); - numVertices++; - vInfos.push_back(vnfo); - currVIdx = vIdx++; - } - } - else if ((vnfo.fU + vnfo.fV) >= ((ScalarType)(1.0 - 1e-5))) - { - std::pair mi = edges.insert(std::make_pair(vmin[2], emptyMap)); - std::pair hi = (*(mi.first)).second.insert(std::make_pair(vmax[2], emptyIsects)); - bool found = false; - for (unsigned int s=0; s<(*(hi.first)).second.n; ++s) - { - if (vClipped[i] == (*(hi.first)).second.isects[s].p) - { - found = true; - vnfo.idx = (unsigned int)(-1); - currVIdx = (*(hi.first)).second.isects[s].idx; - break; - } - } - if (!found) - { - (*(hi.first)).second.isects[(*(hi.first)).second.n].p = vClipped[i]; - (*(hi.first)).second.isects[(*(hi.first)).second.n].idx = vIdx; - (*(hi.first)).second.n++; - - vnfo.idx = (unsigned int)(-1); - numVertices++; - vInfos.push_back(vnfo); - currVIdx = vIdx++; - } - } - else - { - vnfo.idx = (unsigned int)(-1); - numVertices++; - vInfos.push_back(vnfo); - currVIdx = vIdx++; - } - - if (i == 0) - { - firstV = currVIdx; - } - - if (i > 1) - { - tnfo.idx = tIdx++; - tnfo.v[0] = firstV; - tnfo.v[1] = lastV; - tnfo.v[2] = currVIdx; - - tInfos.push_back(tnfo); - } - - lastV = currVIdx; - } - } - } - - if (tInfos.empty()) - { - return; - } - - const unsigned int vSize = (unsigned int)(m.vn); - const unsigned int tSize = (unsigned int)(m.fn); - - typedef Allocator TriMeshAllocatorType; - - TriMeshAllocatorType::AddVertices(r, (int)(vInfos.size())); - TriMeshAllocatorType::AddFaces(r, (int)(tInfos.size())); - - for (size_t i=0; i value + eps; - break; - case 2: - flag = p_in[1] + eps < value; - break; - case 3: - flag = p_in[1] > value + eps; - break; - case 4: - flag = p_in[2] + eps < value; - break; - case 5: - flag = p_in[2] > value + eps; - break; - default: - break; - } - - return (flag); - } - - static inline void CrossPoint(int mode, const ScalarType & value, const CoordType & SP, const CoordType & PP, CoordType & p_out) - { - switch(mode) - { - case 0: - case 1: - p_out[0] = value; - if ((PP[0] - SP[0]) == ((ScalarType)(0))) - { - p_out[1] = PP[1]; - p_out[2] = PP[2]; - } - else - { - p_out[1] = SP[1] + (value - SP[0]) * (PP[1] - SP[1]) / (PP[0] - SP[0]); - p_out[2] = SP[2] + (value - SP[0]) * (PP[2] - SP[2]) / (PP[0] - SP[0]); - } - break; - case 2: - case 3: - p_out[1] = value; - if ((PP[1] - SP[1]) == ((ScalarType)(0))) - { - p_out[0] = PP[0]; - p_out[2] = PP[2]; - } - else - { - p_out[0] = SP[0] + (value - SP[1]) * (PP[0] - SP[0]) / (PP[1] - SP[1]); - p_out[2] = SP[2] + (value - SP[1]) * (PP[2] - SP[2]) / (PP[1] - SP[1]); - } - break; - case 4: - case 5: - p_out[2] = value; - if ((PP[2] - SP[2]) == ((ScalarType)(0))) - { - p_out[0] = PP[0]; - p_out[1] = PP[1]; - } - else - { - p_out[0] = SP[0] + (value - SP[2]) * (PP[0] - SP[0]) / (PP[2] - SP[2]); - p_out[1] = SP[1] + (value - SP[2]) * (PP[1] - SP[1]) / (PP[2] - SP[2]); - } - break; - default: - break; - } - } - - static inline void ClipPolygonLine(int mode, const ScalarType & value, CoordType * P_in, unsigned int n_in, CoordType * P_out, unsigned int & n_out) - { - unsigned int ps; - CoordType * SP; - CoordType * PP; - - n_out = 0; - SP = &P_in[n_in-1]; - - if (ClassType::InRegion(mode, value, *SP)) - { - ps = 0; - } - else - { - ps = 2; - } - - for(unsigned int i=0; i> 1) | ((ClassType::InRegion(mode, value, *PP)) ? (0) : (2)); - - switch(ps) - { - case 0: - break; - case 1: - ClassType::CrossPoint(mode, value, *SP, *PP, P_out[n_out]); - n_out++; - break; - case 2: - ClassType::CrossPoint(mode, value, *SP, *PP, P_out[n_out]); - n_out++; - P_out[n_out] = *PP; - n_out++; - break; - case 3: - P_out[n_out] = *PP; - n_out++; - break; - default: - break; - } - - SP = PP; - } - } - -}; - -} // end namespace tri -} // end namespace vcg - -#endif // __VCGLIB_TRI_CLIP diff --git a/vcg/complex/trimesh/closest.h b/vcg/complex/trimesh/closest.h deleted file mode 100644 index a603a684..00000000 --- a/vcg/complex/trimesh/closest.h +++ /dev/null @@ -1,563 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ -/**************************************************************************** - History - -$Log: not supported by cvs2svn $ -Revision 1.27 2006/12/06 12:59:13 pietroni -added max distance to rayIterator - -Revision 1.26 2006/11/21 16:06:54 ponchio -passing VDistFunct() to functions wanting a reference, not a value -(why a reference btw?) - -Revision 1.25 2006/11/13 13:13:49 ponchio -Added usual typename. - -Revision 1.24 2006/11/12 02:41:03 pietroni -added normalization of normal in DoRay functions - -Revision 1.23 2006/11/10 11:41:49 pietroni -added DoRayFuntion that return interpolated normal - -Revision 1.22 2006/09/20 17:18:26 ponchio -VDistFunct() at line 292 was passed as a temporary. -Invalid under g++. Fixed. - -Revision 1.21 2006/02/09 08:38:04 pietroni -sintax error corrected - -Revision 1.20 2006/02/08 17:02:41 pietroni -commented one GetClosestFace function ... the code is the same then getClosest that return barycentric coordinates - -Revision 1.19 2006/01/10 13:31:54 pietroni -correct pass of variable closest_pt by reference in getclosestFace function - -Revision 1.18 2005/12/02 00:13:34 cignoni -Added and removed typenames for gcc compiling. -removed also some template arguments specifcation that gcc disliked... -commented out GetInSphereFace and SetMesh that are probably never used and i didnt succeed in compile - -Revision 1.17 2005/10/05 17:02:52 pietroni -corrected bugs on GEtKClosestVert and GetInSphereVert - -Revision 1.16 2005/10/03 16:19:07 spinelli -fixed some bugs - -Revision 1.15 2005/10/03 13:59:39 pietroni -added GetInSphere and GetInBox functions -rensmed Functions respectively with Face suffix or Vertex suffix for query on vertex or faces - -Revision 1.14 2005/09/30 13:10:37 pietroni -used functor defined in face/distance.h for distance point-face -used functor defined in intersection3.h for ray-triangle intersection -added GetKClosest and DoRay Functions - -Revision 1.13 2005/09/28 08:30:48 cignoni -changed name of include, removed use of an undefined type (scalar instead of Scalar) -removed unused code portions (the old closest code) - -Revision 1.12 2005/09/21 09:24:30 pietroni -Added RayIterators. -Added ClosestIterators on Triangles and Vertices. -Added Closest Functions on triangles and Vertices. - -Revision 1.11 2005/09/19 13:36:24 pietroni -added ray iterator of faces - -Revision 1.10 2005/09/16 11:53:51 cignoni -Small gcc compliling issues - -Revision 1.9 2005/09/15 13:16:10 spinelli -fixed bugs - -Revision 1.8 2005/09/15 11:15:00 pietroni -minor changes - -Revision 1.7 2005/09/14 12:56:47 pietroni -used closest function from grid - -Revision 1.6 2005/08/26 09:12:48 cignoni -changed typedef A2UGridLink da 'GridStaticPtr::Link' a typedef 'GRID::Link' - -Revision 1.5 2005/02/08 17:49:38 pietroni -added if (!l->Elem()->IsD()) test on each element - -Revision 1.4 2005/01/28 12:00:33 cignoni -small gcc compiling issues for namespaces - -Revision 1.3 2005/01/24 11:47:23 cignoni -Now used also by the official Metro -Removed using namespace (NEVER IN HEADERS!) -Made the computation of barycentric coords only when necessary -Renamed Mindistpoint to Closest - -Revision 1.2 2005/01/21 17:13:09 pietroni -included distance.h changed Dist to vcg::face::PointDistance - -Revision 1.1 2004/10/04 15:32:16 ganovelli -moved from metro core - -Revision 1.6 2004/05/14 00:34:36 ganovelli -header added - -****************************************************************************/ - -#ifndef __VCG_TRIMESH_CLOSEST -#define __VCG_TRIMESH_CLOSEST -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace vcg { - namespace tri { - - //**MARKER CLASSES**// - template - class Tmark - { - MESH_TYPE *m; - public: - Tmark(){} - Tmark( MESH_TYPE *m) {SetMesh(m);} - void UnMarkAll(){ vcg::tri::UnMarkAll(*m);} - bool IsMarked(OBJ_TYPE* obj){return (vcg::tri::IsMarked(*m,obj));} - void Mark(OBJ_TYPE* obj){ vcg::tri::Mark(*m,obj);} - void SetMesh(MESH_TYPE *_m) - {m=_m;} - }; - - template - class FaceTmark:public Tmark - { - public: - FaceTmark() {} - FaceTmark(MESH_TYPE *m) {this->SetMesh(m);} - }; - - template - class VertTmark - { - public: - typedef typename MESH_TYPE::VertexType VertexType; - inline VertTmark(){} - inline VertTmark(MESH_TYPE *){} - inline void UnMarkAll() const {} - inline bool IsMarked(VertexType*) const { return false; } - inline void Mark(VertexType*) const {} - inline void SetMesh(void * /*m=0*/) const {} - }; - - //**CLOSEST FUNCTION DEFINITION**// - - /* - - aka MetroCore - data una mesh m e una ug sulle sue facce trova il punto di m piu' vicino ad - un punto dato. - */ - - // input: mesh, punto, griglia (gr), distanza limite (mdist) - // output: normale (interpolata) alla faccia e punto piu' vicino su di essa, e coord baricentriche del punto trovato - - // Nota che il parametro template GRID non ci dovrebbe essere, visto che deve essere - // UGrid, ma non sono riuscito a definirlo implicitamente - - template - typename MESH::FaceType * GetClosestFace( MESH & mesh, GRID & gr, const typename GRID::CoordType & _p, - const typename GRID::ScalarType & _maxDist, typename GRID::ScalarType & _minDist, - typename GRID::CoordType &_closestPt, typename GRID::CoordType & _normf, - typename GRID::CoordType & _ip) - { - typedef typename GRID::ScalarType ScalarType; - typedef Point3 Point3x; - - typedef FaceTmark MarkerFace; - MarkerFace mf(&mesh); - vcg::face::PointDistanceFunctor FDistFunct; - _minDist=_maxDist; - typename MESH::FaceType* bestf= gr.GetClosest(FDistFunct, mf, _p, _maxDist, _minDist, _closestPt); - - if(_maxDist> ScalarType(fabs(_minDist))) - { - // f=bestf; - typename MESH::ScalarType alfa, beta, gamma; - //calcolo normale con interpolazione trilineare - InterpolationParameters(*bestf,bestf->N(),_closestPt, alfa, beta, gamma); - _normf = (bestf->V(0)->cN())*alfa+ - (bestf->V(1)->cN())*beta+ - (bestf->V(2)->cN())*gamma ; - _ip=Point3x(alfa,beta,gamma); - //normf.Normalize(); inutile si assume le normali ai vertici benfatte - - _minDist = fabs(_minDist); - return(bestf); - } - return (0); - } - - /*template - typename MESH::FaceType * GetClosestFace( MESH & mesh,GRID & gr,const typename GRID::CoordType & _p, - const typename GRID::ScalarType & _maxDist,typename GRID::ScalarType & _minDist, - typename GRID::CoordType &_closestPt,typename GRID::CoordType & _normf) - { - Point3 _ip; - typedef FaceTmark MarkerFace; - MarkerFace mf; - mf.SetMesh(&mesh); - vcg::face::PointDistanceFunctor FDistFunct; - typename MESH::FaceType* bestf= gr.GetClosest(FDistFunct,mf,_p,_maxDist,_minDist,_closestPt) ); - }*/ - - template - typename MESH::FaceType * GetClosestFace( MESH & mesh,GRID & gr,const typename GRID::CoordType & _p, - const typename GRID::ScalarType & _maxDist,typename GRID::ScalarType & _minDist, - typename GRID::CoordType &_closestPt) - { - typedef typename GRID::ScalarType ScalarType; - typedef Point3 Point3x; - typedef FaceTmark MarkerFace; - MarkerFace mf; - mf.SetMesh(&mesh); - vcg::face::PointDistanceFunctor PDistFunct; - _minDist=_maxDist; - return (gr.GetClosest(PDistFunct,mf,_p,_maxDist,_minDist,_closestPt)); - } - - template - typename MESH::FaceType * GetClosestFaceNormal(MESH & mesh,GRID & gr,const typename MESH::VertexType & _p, - const typename GRID::ScalarType & _maxDist,typename GRID::ScalarType & _minDist, - typename GRID::CoordType &_closestPt) - { - typedef typename GRID::ScalarType ScalarType; - typedef FaceTmark MarkerFace; - MarkerFace mf; - mf.SetMesh(&mesh); - typedef vcg::face::PointNormalDistanceFunctor PDistFunct; - PDistFunct fn; - _minDist=_maxDist; - //return (gr.GetClosest(PDistFunct,mf,_p,_maxDist,_minDist,_closestPt.P())); - return (gr.template GetClosest (fn,mf,_p,_maxDist,_minDist,_closestPt)); - } - - template - typename MESH::VertexType * GetClosestVertex( MESH & mesh,GRID & gr,const typename GRID::CoordType & _p, - const typename GRID::ScalarType & _maxDist,typename GRID::ScalarType & _minDist ) - { - typedef typename GRID::ScalarType ScalarType; - typedef Point3 Point3x; - typedef VertTmark MarkerVert; - MarkerVert mv; - mv.SetMesh(&mesh); - typedef vcg::vertex::PointDistanceFunctor VDistFunct; - VDistFunct fn; - _minDist=_maxDist; - Point3x _closestPt; - return (gr.template GetClosest(fn,mv,_p,_maxDist,_minDist,_closestPt)); - } - - template - typename MESH::VertexType * GetClosestVertexNormal( MESH & mesh,GRID & gr,const typename MESH::VertexType & _p, - const typename GRID::ScalarType & _maxDist,typename GRID::ScalarType & _minDist ) - { - typedef typename GRID::ScalarType ScalarType; - typedef Point3 Point3x; - typedef VertTmark MarkerVert; - MarkerVert mv; - mv.SetMesh(&mesh); - typedef vcg::vertex::PointNormalDistanceFunctor VDistFunct; - VDistFunct fn; - _minDist=_maxDist; - Point3x _closestPt; - return (gr.template GetClosest (fn,mv,_p,_maxDist,_minDist,_closestPt)); - } - - template - unsigned int GetKClosestFace(MESH & mesh,GRID & gr, const unsigned int _k, - const typename GRID::CoordType & _p, const typename GRID::ScalarType & _maxDist, - OBJPTRCONTAINER & _objectPtrs,DISTCONTAINER & _distances, POINTCONTAINER & _points) - { - typedef FaceTmark MarkerFace; - MarkerFace mf; - mf.SetMesh(&mesh); - vcg::face::PointDistanceFunctor FDistFunct; - return (gr.GetKClosest /**/ - (FDistFunct,mf,_k,_p,_maxDist,_objectPtrs,_distances,_points)); - } - - // This version does not require that the face type has the - // EdgePlane component and use a less optimized (but more memory efficient) point-triangle distance - template - unsigned int GetKClosestFaceBase(MESH & mesh,GRID & gr, const unsigned int _k, - const typename GRID::CoordType & _p, const typename GRID::ScalarType & _maxDist, - OBJPTRCONTAINER & _objectPtrs,DISTCONTAINER & _distances, POINTCONTAINER & _points) - { - typedef FaceTmark MarkerFace; - MarkerFace mf; - mf.SetMesh(&mesh); - vcg::face::PointDistanceBaseFunctor FDistFunct; - return (gr.GetKClosest /**/ - (FDistFunct,mf,_k,_p,_maxDist,_objectPtrs,_distances,_points)); - } - - template - unsigned int GetKClosestVertex(MESH & mesh,GRID & gr, const unsigned int _k, - const typename GRID::CoordType & _p, const typename GRID::ScalarType & _maxDist, - OBJPTRCONTAINER & _objectPtrs,DISTCONTAINER & _distances, POINTCONTAINER & _points) - { - typedef VertTmark MarkerVert; - MarkerVert mv; - mv.SetMesh(&mesh); - typedef vcg::vertex::PointDistanceFunctor VDistFunct; - VDistFunct distFunct; - return (gr.GetKClosest/* */ - (distFunct,mv,_k,_p,_maxDist,_objectPtrs,_distances,_points)); - } - - template - unsigned int GetInSphereFace(MESH & mesh, - GRID & gr, - const typename GRID::CoordType & _p, - const typename GRID::ScalarType & _r, - OBJPTRCONTAINER & _objectPtrs, - DISTCONTAINER & _distances, - POINTCONTAINER & _points) - { - typedef FaceTmark MarkerFace; - MarkerFace mf; - mf.SetMesh(&mesh); - typedef vcg::face::PointDistanceFunctor FDistFunct; - return (gr.GetInSphere/**/ - (FDistFunct(),mf,_p,_r,_objectPtrs,_distances,_points)); - } - - template - unsigned int GetInSphereVertex(MESH & mesh, - GRID & gr, - const typename GRID::CoordType & _p, - const typename GRID::ScalarType & _r, - OBJPTRCONTAINER & _objectPtrs, - DISTCONTAINER & _distances, - POINTCONTAINER & _points) - { - typedef VertTmark MarkerVert; - MarkerVert mv; - mv.SetMesh(&mesh); - typedef vcg::vertex::PointDistanceFunctor VDistFunct; - VDistFunct fn; - return (gr.GetInSphere/**/ - (fn, mv,_p,_r,_objectPtrs,_distances,_points)); - } - - template - unsigned int GetInBoxFace(MESH & mesh, - GRID & gr, - const vcg::Box3 _bbox, - OBJPTRCONTAINER & _objectPtrs) - { - typedef FaceTmark MarkerFace; - MarkerFace mf; - mf.SetMesh(&mesh); - return(gr.GetInBox/**/(mf,_bbox,_objectPtrs)); - } - - template - unsigned int GetInBoxVertex(MESH & mesh, - GRID & gr, - const vcg::Box3 _bbox, - OBJPTRCONTAINER & _objectPtrs) - { - typedef VertTmark MarkerVert; - MarkerVert mv; - mv.SetMesh(&mesh); - return(gr.GetInBox/**/(mv,_bbox,_objectPtrs)); - } - - template - typename GRID::ObjPtr DoRay(MESH & mesh,GRID & gr, const Ray3 & _ray, - const typename GRID::ScalarType & _maxDist, typename GRID::ScalarType & _t) - { - typedef typename MESH::FaceType FaceType; - typedef typename MESH::ScalarType ScalarType; - typedef FaceTmark MarkerFace; - MarkerFace mf; - mf.SetMesh(&mesh); - Ray3 _ray1=_ray; - _ray1.Normalize(); - typedef vcg::RayTriangleIntersectionFunctor FintFunct; - FintFunct ff; - return(gr.DoRay(ff,mf,_ray1,_maxDist,_t)); - } - - template - typename GRID::ObjPtr DoRay(MESH & mesh,GRID & gr, const Ray3 & _ray, - const typename GRID::ScalarType & _maxDist, - typename GRID::ScalarType & _t, - typename GRID::CoordType & _normf) - { - typedef typename MESH::FaceType FaceType; - typedef typename MESH::ScalarType ScalarType; - typedef FaceTmark MarkerFace; - MarkerFace mf; - mf.SetMesh(&mesh); - typedef vcg::RayTriangleIntersectionFunctor FintFunct; - FintFunct fintfunct; - Ray3 _ray1=_ray; - _ray1.Normalize(); - FaceType *f=gr.DoRay(fintfunct,mf,_ray1,_maxDist,_t); - typename GRID::CoordType dir=_ray.Direction(); - dir.Normalize(); - typename GRID::CoordType int_point=_ray.Origin()+_ray1.Direction()*_t; - typename GRID::ScalarType alfa,beta,gamma; - if (f!=NULL) - { - InterpolationParameters(*f,f->N(),int_point, alfa, beta, gamma); - _normf = (f->V(0)->cN())*alfa+ - (f->V(1)->cN())*beta+ - (f->V(2)->cN())*gamma ; - } - return f; - } - - ///Iteratively Do Ray sampling on spherical coordinates - ///sampling along the two angles - template - void RaySpherical(MESH & mesh,GRID & gr, const Ray3 & _ray, - const typename GRID::ScalarType & _maxDist, - const typename GRID::ScalarType & _theta_interval, - const typename GRID::ScalarType & _phi_interval, - const int &n_samples, - OBJPTRCONTAINER & _objectPtrs, - COORDCONTAINER & _pos, - COORDCONTAINER & _norm) - { - typedef typename MESH::FaceType FaceType; - typedef typename MESH::ScalarType ScalarType; - ScalarType delta_theta=_theta_interval/(ScalarType)(n_samples*2); - ScalarType delta_phi =_phi_interval/(ScalarType)(n_samples*2); - ScalarType theta_init,phi_init,ro; - typename GRID::CoordType dir0=_ray.Direction(); - dir0.ToPolarRad(ro,theta_init,phi_init); - for (int x=-n_samples;x<=n_samples;x++) - for (int y=-n_samples;y<=n_samples;y++) - { - ScalarType theta=theta_init+x*delta_theta; - if (theta<0) theta=2.0*M_PI-theta; - ScalarType phi=phi_init+y*delta_phi; - - typename GRID::CoordType dir; - dir.FromxPolar(ro,theta,phi); - dir.Normalize(); - Ray3 curr_ray(_ray.Origin(),dir); - typename GRID::ScalarType _t; - typename GRID::ObjPtr f=NULL; - f=DoRay(mesh,gr,curr_ray,_maxDist,_t); - if (f!=NULL) - { - typename GRID::CoordType pos=curr_ray.Origin()+curr_ray.Direction()*_t; - _objectPtrs.push_back(f); - _pos.push_back(pos); - - ///find the normal - typename GRID::ScalarType alfa,beta,gamma; - InterpolationParameters(*f,*f.N(),pos, alfa, beta, gamma); - typename GRID::CoordType norm = (f->V(0)->cN())*alfa+ - (f->V(1)->cN())*beta+ - (f->V(2)->cN())*gamma ; - _norm.push_back(norm); - } - } - } - - //**ITERATORS DEFINITION**// - - template - class ClosestFaceIterator:public vcg::ClosestIterator, FaceTmark > - { - public: - typedef GRID GridType; - typedef MESH MeshType; - typedef FaceTmark MarkerFace; - typedef vcg::face::PointDistanceFunctor PDistFunct; - typedef vcg::ClosestIterator > ClosestBaseType; - typedef typename MESH::FaceType FaceType; - typedef typename MESH::ScalarType ScalarType; - - //ClosestFaceIterator(GridType &_Si):ClosestBaseType(_Si,PDistFunct()){} - ClosestFaceIterator(GridType &_Si):ClosestBaseType(_Si,PDistFunct()){} - -// Commented out: it seems unuseful and make gcc complain. p. - void SetMesh(MeshType *m) - {this->tm.SetMesh(m);} - }; - - template - class ClosestVertexIterator:public vcg::ClosestIterator, VertTmark > - { - public: - typedef GRID GridType; - typedef MESH MeshType; - typedef VertTmark MarkerVert; - typedef vcg::vertex::PointDistanceFunctor VDistFunct; - typedef vcg::ClosestIterator > ClosestBaseType; - VDistFunct fn; - ClosestVertexIterator(GridType &_Si):ClosestBaseType(_Si,fn){} - -// Commented out: it seems unuseful and make gcc complain. p. - void SetMesh(MeshType *m) - {this->tm.SetMesh(m);} - }; - - template - class TriRayIterator:public vcg::RayIterator,FaceTmark > - { - public: - typedef GRID GridType; - typedef MESH MeshType; - typedef FaceTmark MarkerFace; - typedef vcg::RayTriangleIntersectionFunctor FintFunct; - typedef vcg::RayIterator > RayBaseType; - typedef typename MESH::FaceType FaceType; - typedef typename MESH::ScalarType ScalarType; - - TriRayIterator(GridType &_Si,const ScalarType &max_d):RayBaseType(_Si,FintFunct(),max_d){} - -// Commented out: it seems unuseful and make gcc complain. p. - void SetMesh(MeshType *m) - {this->tm.SetMesh(m);} - - }; - - } // end namespace tri -} // end namespace vcg - -#endif diff --git a/vcg/complex/trimesh/clustering.h b/vcg/complex/trimesh/clustering.h deleted file mode 100644 index 1a67a5b9..00000000 --- a/vcg/complex/trimesh/clustering.h +++ /dev/null @@ -1,436 +0,0 @@ -/**************************************************************************** - * VCGLib o o * - * Visual and Computer Graphics Library o o * - * _ O _ * - * Copyright(C) 2006 \/)\/ * - * Visual Computing Lab /\/| * - * ISTI - Italian National Research Council | * - * \ * - * All rights reserved. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * - * for more details. * - * * - ****************************************************************************/ -/**************************************************************************** - History - -$Log: not supported by cvs2svn $ -Revision 1.11 2006/06/08 13:55:16 cignoni -Added ColorPreserving Cellbase template. - -Revision 1.10 2006/05/26 10:18:11 cignoni -Re-adapted to ms compilers - -Revision 1.9 2006/05/25 09:37:14 cignoni -Many changes for the different interpretation of hash_set between gcc and .net. Probably to be completed. - -Revision 1.8 2006/05/24 16:42:22 m_di_benedetto -Corrected bbox inflation amount in case of _cellsize != 0 - -Revision 1.7 2006/05/24 15:16:01 cignoni -better comment to the init parameters - -Revision 1.6 2006/05/24 08:54:04 cignoni -Added missing std:: to swap - -Revision 1.5 2006/05/21 06:40:31 cignoni -Added DoubleFace management - -Revision 1.4 2006/05/19 20:49:03 m_di_benedetto -Added check for empty generated mesh (prevent call to mesh allocator with zero vertices or faces). - -Revision 1.3 2006/05/18 22:20:53 m_di_benedetto -added check for deleted faces and modified/added std namespace qualifier. - -Revision 1.2 2006/05/18 13:59:20 cignoni -Some minor optimizations - -Revision 1.1 2006/05/16 21:56:06 cignoni -First working Version - -****************************************************************************/ - -#ifndef __VCGLIB_CLUSTERING -#define __VCGLIB_CLUSTERING - -#include -#include -#include -#include -#include - -#include -#include -#include - -// some stuff for portable hashes... -#ifdef WIN32 - #ifndef __MINGW32__ - #include - #include - #define STDEXT stdext - #else - #include - #include - #define STDEXT __gnu_cxx - #endif -#else - #include - #include - #define STDEXT __gnu_cxx -#endif - - - -namespace vcg{ -namespace tri{ -#define HASH_P0 73856093 -#define HASH_P1 19349663 -#define HASH_P2 83492791 - -class HashedPoint3i : public Point3i -{ -public: - - size_t Hash() const - { - return (V(0)*HASH_P0 ^ V(1)*HASH_P1 ^ V(2)*HASH_P2); - } - - operator size_t () const - {return Hash();} -}; - -// needed for gcc compilation -#ifndef _MSC_VER -}} namespace STDEXT { - template <> struct hash{ - inline size_t operator ()(const vcg::tri::HashedPoint3i &p) const {return size_t(p);} -}; -} namespace vcg{ namespace tri{ -#endif - -// -template -class NearestToCenter -{ - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::FaceType FaceType; - typedef BasicGrid GridType; - - public: - inline void AddVertex(MeshType &/*m*/, GridType &g, Point3i &pi, VertexType &v) - { - CoordType c; - g.IPiToBoxCenter(pi,c); - ScalarType newDist = Distance(c,v.cP()); - if(!valid || newDist < bestDist) - { - valid=true; - bestDist=newDist; - bestPos=v.cP(); - bestN=v.cN(); - orig=&v; - } - } - inline void AddFaceVertex(MeshType &m, FaceType &f, int i) { assert(0);} - NearestToCenter(): valid(false){} - - CoordType bestPos; - CoordType bestN; - ScalarType bestDist; - bool valid; - int id; - VertexType *orig; - CoordType Pos() const - { - assert(valid); - return bestPos; - } - Color4b Col() const {return Color4b::White;} - CoordType N() const {return bestN;} - VertexType * Ptr() const {return orig;} - -}; - - - -template -class AverageColorCell -{ - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::VertexType VertexType; - - typedef BasicGrid GridType; - - public: - inline void AddFaceVertex(MeshType &/*m*/, FaceType &f, int i) - { - p+=f.cV(i)->cP(); - c+=CoordType(f.cV(i)->C()[0],f.cV(i)->C()[1],f.cV(i)->C()[2]); - - // we prefer to use the un-normalized face normal so small faces facing away are dropped out - // and the resulting average is weighed with the size of the faces falling here. - n+=f.cN(); - cnt++; - } - inline void AddVertex(MeshType &/*m*/, GridType &/*g*/, Point3i &/*pi*/, VertexType &v) - { - p+=v.cP(); - n+=v.cN(); - c+=CoordType(v.C()[0],v.C()[1],v.C()[2]); - cnt++; - } - - AverageColorCell(): p(0,0,0), n(0,0,0), c(0,0,0),cnt(0){} - CoordType p; - CoordType n; - CoordType c; - int cnt; - int id; - Color4b Col() const - { - return Color4b(c[0]/cnt,c[1]/cnt,c[2]/cnt,255); - } - - CoordType N() const {return n;} - VertexType * Ptr() const {return 0;} - CoordType Pos() const { return p/cnt; } -}; - - -/* - Metodo di clustering -*/ -template -class Clustering -{ - public: - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::FaceIterator FaceIterator; - - // DuplicateFace == bool means that during the clustering doublesided surface (like a thin shell) that would be clustered to a single surface - // will be merged into two identical but opposite faces. - // So in practice: - // DuplicateFace=true a model with looks ok if you enable backface culling - // DuplicateFace=false a model with looks ok if you enable doublesided lighting and disable backfaceculling - - bool DuplicateFaceParam; - - // This class keeps the references to the three cells where a face has its vertexes. - class SimpleTri - { - public: - CellType *v[3]; - int ii(int i) const {return *((int *)(&(v[i])));} - bool operator < ( const SimpleTri &p) const { - return (v[2]!=p.v[2])?(v[2] v[1] ) std::swap(v[0],v[1]); // now v0 < v1 - if(v[0] > v[2] ) std::swap(v[0],v[2]); // now v0 is the minimum - if(v[1] > v[2] ) std::swap(v[1],v[2]); // sorted! - } - // Hashing Function; - operator size_t () const - { - return (ii(0)*HASH_P0 ^ ii(1)*HASH_P1 ^ ii(2)*HASH_P2); - } - }; - - - // The init function Take two parameters - // _size is the approximate total number of cells composing the grid surrounding the objects (usually a large number) - // eg _size==1.000.000 means a 100x100x100 grid - // _cellsize is the absolute lenght of the edge of the grid cell. - // eg _cellsize==2.0 means that all the vertexes in a 2.0x2.0x2.0 cell are clustered togheter - - // Notes: - // _size is used only if the cell edge IS zero. - // _cellsize gives you an absolute measure of the maximum error introduced - // during the simplification (e.g. half of the cell edge lenght) - - - void Init(Box3 _mbb, int _size, ScalarType _cellsize=0) - { - GridCell.clear(); - TriSet.clear(); - Grid.bbox=_mbb; - ///inflate the bb calculated - ScalarType infl = (_cellsize == (ScalarType)0) ? (Grid.bbox.Diag() / _size) : (_cellsize); - Grid.bbox.min-=CoordType(infl,infl,infl); - Grid.bbox.max+=CoordType(infl,infl,infl); - Grid.dim = Grid.bbox.max - Grid.bbox.min; - if( _cellsize==0) - BestDim( _size, Grid.dim, Grid.siz ); - else - Grid.siz = Point3i::Construct(Grid.dim / _cellsize); - - // find voxel size - Grid.voxel[0] = Grid.dim[0]/Grid.siz[0]; - Grid.voxel[1] = Grid.dim[1]/Grid.siz[1]; - Grid.voxel[2] = Grid.dim[2]/Grid.siz[2]; - } - - - BasicGrid Grid; - -#ifdef _MSC_VER - STDEXT::hash_set TriSet; - typedef typename STDEXT::hash_set::iterator TriHashSetIterator; -#else - struct SimpleTriHashFunc{ - inline size_t operator ()(const SimpleTri &p) const {return size_t(p);} - }; - STDEXT::hash_set TriSet; - typedef typename STDEXT::hash_set::iterator TriHashSetIterator; -#endif - - STDEXT::hash_map GridCell; - - - void AddPointSet(MeshType &m, bool UseOnlySelected=false) - { - VertexIterator vi; - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - if(!(*vi).IsD()) - if(!UseOnlySelected || (*vi).IsS()) - { - HashedPoint3i pi; - Grid.PToIP((*vi).cP(), pi ); - GridCell[pi].AddVertex(m,Grid,pi,*(vi)); - } - } - - void AddMesh(MeshType &m) - { - FaceIterator fi; - for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) - { - HashedPoint3i pi; - SimpleTri st; - for(int i=0;i<3;++i) - { - Grid.PToIP((*fi).cV(i)->cP(), pi ); - st.v[i]=&(GridCell[pi]); - st.v[i]->AddFaceVertex(m,*(fi),i); - } - if( (st.v[0]!=st.v[1]) && (st.v[0]!=st.v[2]) && (st.v[1]!=st.v[2]) ) - { // if we allow the duplication of faces we sort the vertex only partially (to maintain the original face orientation) - if(DuplicateFaceParam) st.sortOrient(); - else st.sort(); - TriSet.insert(st); - } - // printf("Inserted %8i triangles, clustered to %8i tri and %i cells\n",distance(m.face.begin(),fi),TriSet.size(),GridCell.size()); - } - } - - int CountPointSet() {return GridCell.size(); } - - void SelectPointSet(MeshType &m) - { - typename STDEXT::hash_map::iterator gi; - UpdateSelection::ClearVertex(m); - for(gi=GridCell.begin();gi!=GridCell.end();++gi) - { - VertexType *ptr=(*gi).second.Ptr(); - if(ptr && ( ptr >= &*m.vert.begin() ) && ( ptr <= &*(m.vert.end() - 1) ) ) - ptr->SetS(); - } - } - void ExtractPointSet(MeshType &m) - { - m.Clear(); - - if (GridCell.empty()) return; - - Allocator::AddVertices(m,GridCell.size()); - typename STDEXT::hash_map::iterator gi; - int i=0; - for(gi=GridCell.begin();gi!=GridCell.end();++gi) - { - m.vert[i].P()=(*gi).second.Pos(); - m.vert[i].N()=(*gi).second.N(); - m.vert[i].C()=(*gi).second.Col(); - ++i; - } - - } - - void ExtractMesh(MeshType &m) - { - m.Clear(); - - if (TriSet.empty() || GridCell.empty()) - { - return; - } - - Allocator::AddVertices(m,GridCell.size()); - typename STDEXT::hash_map::iterator gi; - int i=0; - for(gi=GridCell.begin();gi!=GridCell.end();++gi) - { - m.vert[i].P()=(*gi).second.Pos(); - if(m.vert[i].HasColor()) - m.vert[i].C()=(*gi).second.Col(); - (*gi).second.id=i; - ++i; - } - Allocator::AddFaces(m,TriSet.size()); - TriHashSetIterator ti; - i=0; - for(ti=TriSet.begin();ti!=TriSet.end();++ti) - { - m.face[i].V(0)=&(m.vert[(*ti).v[0]->id]); - m.face[i].V(1)=&(m.vert[(*ti).v[1]->id]); - m.face[i].V(2)=&(m.vert[(*ti).v[2]->id]); - // if we are merging faces even when opposite we choose - // the best orientation according to the averaged normal - if(!DuplicateFaceParam) - { - CoordType N=vcg::Normal(m.face[i]); - int badOrient=0; - if( N.dot((*ti).v[0]->N()) <0) ++badOrient; - if( N.dot((*ti).v[1]->N()) <0) ++badOrient; - if( N.dot((*ti).v[2]->N()) <0) ++badOrient; - if(badOrient>2) - std::swap(m.face[i].V(0),m.face[i].V(1)); - } - i++; - } - - } -}; //end class clustering - } // namespace tri -} // namespace vcg - -#endif diff --git a/vcg/complex/trimesh/crease_cut.h b/vcg/complex/trimesh/crease_cut.h deleted file mode 100644 index 572ea229..00000000 --- a/vcg/complex/trimesh/crease_cut.h +++ /dev/null @@ -1,147 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2008 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ - -#ifndef __VCG_CREASE_CUT -#define __VCG_CREASE_CUT -#include -#include -#include -namespace vcg { -namespace tri { - -/* -Crease Angle -Assume che: -la mesh abbia la topologia ff -la mesh non abbia complex (o se li aveva fossero stati detached) -Abbia le normali per faccia normalizzate!! - - -Prende una mesh e duplica tutti gli edge le cui normali nelle facce incidenti formano un angolo maggiore -di (espresso in rad). -foreach face - foreach unvisited vert vi - scan the star of triangles around vi duplicating vi each time we encounter a crease angle. - -the new (and old) vertexes are put in a std::vector that is swapped with the original one at the end. - -Si tiene un vettore di interi 3 *fn che dice l'indice del vertice puntato da ogni faccia. -quando si scandisce la stella intorno ad un vertici, per ogni wedge si scrive l'indice del vertice corrsipondente. - - -*/ - -template -void CreaseCut(MESH_TYPE &m, float angleRad) -{ - typedef typename MESH_TYPE::CoordType CoordType; - typedef typename MESH_TYPE::ScalarType ScalarType; - typedef typename MESH_TYPE::VertexType VertexType; - typedef typename MESH_TYPE::VertexPointer VertexPointer; - typedef typename MESH_TYPE::VertexIterator VertexIterator; - typedef typename MESH_TYPE::FaceIterator FaceIterator; - typedef typename MESH_TYPE::FaceType FaceType; - typedef typename MESH_TYPE::FacePointer FacePointer; - - tri::Allocator::CompactVertexVector(m); - tri::Allocator::CompactFaceVector(m); - - tri::UpdateNormals::NormalizeFace(m); - - assert(tri::HasFFAdjacency(m)); - typename MESH_TYPE::ScalarType cosangle=math::Cos(angleRad); - - tri::UpdateFlags::VertexClearV(m); - std::vector indVec(m.fn*3,-1); - int newVertexCounter=m.vn; - int creaseCounter=0; - int startVn=m.vn; - FaceIterator fi; - //const FaceType * nextf; - for(fi=m.face.begin();fi!=m.face.end();++fi) - for(int j=0;j<3;++j) - if(!(*fi).V(j)->IsV() ) // foreach unvisited vertex we loop around it searching for creases. - { - (*fi).V(j)->SetV(); - - face::JumpingPos iPos(&*fi,j,(*fi).V(j)); - size_t vertInd = Index(m,iPos.v); // - bool isBorderVertex = iPos.FindBorder(); // for border vertex we start from the border. - face::JumpingPos startPos=iPos; - if(!isBorderVertex) // for internal vertex we search the first crease and start from it - { - do { - ScalarType dotProd = iPos.FFlip()->cN().dot(iPos.f->N()); - iPos.NextFE(); - if(dotProdcN().dot(iPos.f->N()); // test normal with the next face (fflip) - size_t faceInd = Index(m,iPos.f); - indVec[faceInd*3+ iPos.VInd()] = curVertexCounter; - - if(dotProd0 && (!isBorderVertex) ) newVertexCounter--; - } - - // A questo punto ho un vettore che mi direbbe per ogni faccia quale vertice devo mettere. Dopo che ho aggiunto i vertici necessari, - // rifaccio il giro delle facce - qDebug("adding %i vert for %i crease edges ",newVertexCounter-m.vn, creaseCounter); - tri::Allocator::AddVertices(m,newVertexCounter-m.vn); - - tri::UpdateFlags::VertexClearV(m); - for(fi=m.face.begin();fi!=m.face.end();++fi) - for(int j=0;j<3;++j) // foreach unvisited vertex - { - size_t faceInd = Index(m, *fi); - size_t vertInd = Index(m, (*fi).V(j)); - int curVertexInd = indVec[faceInd*3+ j]; - assert(curVertexInd != -1); - assert(curVertexInd < m.vn); - if(curVertexInd < startVn) assert(size_t(curVertexInd) == vertInd); - if(curVertexInd >= startVn) - { - m.vert[curVertexInd].ImportData(*((*fi).V(j))); - (*fi).V(j) = & m.vert[curVertexInd]; - } - } - tri::UpdateNormals::PerVertexFromCurrentFaceNormal(m); -} - -} // end namespace tri -} // end namespace vcg -#endif - diff --git a/vcg/complex/trimesh/edge_collapse.h b/vcg/complex/trimesh/edge_collapse.h deleted file mode 100644 index afde69f8..00000000 --- a/vcg/complex/trimesh/edge_collapse.h +++ /dev/null @@ -1,372 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ -/**************************************************************************** - History - $Log: not supported by cvs2svn $ - Revision 1.16 2006/10/07 15:04:25 cignoni - removed a useless include - - Revision 1.15 2005/10/12 10:36:26 cignoni - Removed unused local type Edge. Now it use the standard simplex edge. - - Revision 1.14 2004/12/10 01:04:42 cignoni - better comments - - Revision 1.13 2004/11/23 10:34:45 cignoni - passed parameters by reference in many funcs and gcc cleaning - - -****************************************************************************/ - -#ifndef __VCG_TETRA_TRI_COLLAPSE -#define __VCG_TETRA_TRI_COLLAPSE - - -#include -#include -#include - -namespace vcg{ -namespace tri{ - -/** \addtogroup trimesh */ -/*@{*/ -/** This a static utility class for the edge collapse. - It provides a common set of useful function for actually making an edge collapse over a trimesh. - See also the corresponding class in the local optimization framework called TriEdgeCollapse -**/ - -template -class EdgeCollapse -{ - public: - /// The tetrahedral mesh type - typedef TRI_MESH_TYPE TriMeshType; - /// The tetrahedron type - typedef typename TriMeshType::FaceType FaceType; - /// The vertex type - typedef typename FaceType::VertexType VertexType; - typedef typename FaceType::VertexPointer VertexPointer; - /// The vertex iterator type - typedef typename TriMeshType::VertexIterator VertexIterator; - /// The tetra iterator type - typedef typename TriMeshType::FaceIterator FaceIterator; - /// The coordinate type - typedef typename FaceType::VertexType::CoordType CoordType; - /// The scalar type - typedef typename TriMeshType::VertexType::ScalarType ScalarType; - ///the container of tetrahedron type - typedef typename TriMeshType::FaceContainer FaceContainer; - ///the container of vertex type - typedef typename TriMeshType::VertContainer VertContainer; - ///half edge type - typedef typename TriMeshType::FaceType::EdgeType EdgeType; - /// vector of pos - typedef typename std::vector EdgeVec; - ///of VFIterator - typedef typename vcg::face::VFIterator VFI; - /// vector of VFIterator - typedef typename std::vector > VFIVec; - - - - /// Default Constructor - EdgeCollapse() - { - }; - - ~EdgeCollapse() - { - }; - - static VFIVec & AV0(){static VFIVec av0; return av0;} - static VFIVec & AV1(){static VFIVec av1; return av1;} - static VFIVec & AV01(){static VFIVec av01; return av01;} - - - void FindSets(EdgeType &p) - { - VertexType * v0 = p.V(0); - VertexType * v1 = p.V(1); - - AV0().clear(); // Facce incidenti in v0 - AV1().clear(); // Facce incidenti in v1 - AV01().clear(); // Facce incidenti in v0 e v1 - - VFI x; - - for( x.f = v0->VFp(), x.z = v0->VFi(); x.f!=0; ++x) - { - int zv1 = -1; - - for(int j=0;j<3;++j) - if( x.f->V(j)==&*v1 ) { - zv1 = j; - break; - } - if(zv1==-1) AV0().push_back( x ); // la faccia x.f non ha il vertice v1 => e' incidente solo in v0 - else AV01().push_back( x ); - } - - for( x.f = v1->VFp(), x.z = v1->VFi(); x.f!=0; ++x ) - { - int zv0 = -1; - - for(int j=0;j<3;++j) - if( x.f->V(j)==&*v0 ) { - zv0 = j; - break; - } - if(zv0==-1) AV1().push_back( x ); // la faccia x.f non ha il vertice v1 => e' incidente solo in v0 - } -} -/* - Link Conditions test, as described in - - Topology Preserving Edge Contraction - T. Dey, H. Edelsbrunner, - Pub. Inst. Math. 1999 - - Lk (sigma) is the set of all the faces of the cofaces of sigma that are disjoint from sigma - - Lk(v0) inters Lk(v1) == Lk(v0-v1) - - To perform these tests using only the VF adjacency we resort to some virtual counters over - the vertices and the edges, we implement them as std::maps, and we increase these counters - by running over all the faces around each vertex of the collapsing edge. - - At the end (after adding dummy stuff) we should have - 2 for vertices not shared - 4 for vertices shared - 2 for edges shared - 1 for edges not shared. - - -*/ - bool LinkConditions(EdgeType pos) - { - typedef typename vcg::face::VFIterator VFIterator; - // at the end of the loop each vertex must be counted twice - // except for boundary vertex. - std::map VertCnt; - std::map,int> EdgeCnt; - - // the list of the boundary vertexes for the two endpoints - std::vector BoundaryVertexVec[2]; - - // Collect vertexes and edges of V0 and V1 - VFIterator vfi; - for(int i=0;i<2;++i) - { - vfi = VFIterator(pos.V(i)); - for( ;!vfi.End();++vfi) - { - ++ VertCnt[vfi.V1()]; - ++ VertCnt[vfi.V2()]; - if(vfi.V1()::iterator vcmit; - for(vcmit=VertCnt.begin();vcmit!=VertCnt.end();++vcmit) - { - if((*vcmit).second==1) // boundary vertexes are counted only once - BoundaryVertexVec[i].push_back((*vcmit).first); - } - if(BoundaryVertexVec[i].size()==2) - { // aha! one of the two vertex of the collapse is on the boundary - // so add dummy vertex and two dummy edges - VertCnt[0]+=2; - ++ EdgeCnt[std::make_pair(VertexPointer(0),BoundaryVertexVec[i][0]) ] ; - ++ EdgeCnt[std::make_pair(VertexPointer(0),BoundaryVertexVec[i][1]) ] ; - // remember to hide the boundaryness of the two boundary vertexes - ++VertCnt[BoundaryVertexVec[i][0]]; - ++VertCnt[BoundaryVertexVec[i][1]]; - } - } - - // Final loop to find cardinality of Lk( V0-V1 ) - // Note that Lk(edge) is only a set of vertices. - std::vector LkEdge; - - for( vfi = VFIterator(pos.V(0)); !vfi.End(); ++vfi) - { - if(vfi.V1() == pos.V(1) ) LkEdge.push_back(vfi.V2()); - if(vfi.V2() == pos.V(1) ) LkEdge.push_back(vfi.V1()); - } - - // if the collapsing edge was a boundary edge, we must add the dummy vertex. - // Note that this implies that Lk(edge) >=2; - if(LkEdge.size()==1) - { - LkEdge.push_back(0); - } - - // NOW COUNT!!! - size_t SharedEdgeCnt=0; - typename std::map, int>::iterator eci; - for(eci=EdgeCnt.begin();eci!=EdgeCnt.end();++eci) - if((*eci).second == 2) SharedEdgeCnt ++; - - if(SharedEdgeCnt>0) return false; - size_t SharedVertCnt=0; - typename std::map::iterator vci; - for(vci=VertCnt.begin();vci!=VertCnt.end();++vci) - if((*vci).second == 4) SharedVertCnt++; - - if(SharedVertCnt != LkEdge.size() ) return false; - - return true; - } - - - - bool LinkConditionsOld(EdgeType pos){ - - const int ADJ_1 = TriMeshType::VertexType::NewBitFlag(); - const int ADJ_E = TriMeshType::VertexType::NewBitFlag(); - //enum {ADJ_1= MeshType::VertexType::USER0, - // ADJ_E= MeshType::VertexType::USER0<<1} ; - // const int ALLADJ = ADJ_1|ADJ_E; - const int NOTALLADJ = ~(ADJ_1 | ADJ_E | TriMeshType::VertexType::VISITED); - const int NOTALLADJ1 = ~(ADJ_E | TriMeshType::VertexType::VISITED); - - //EdgePosB x; - typename vcg::face::VFIterator x; - // Clear visited and adj flag for all vertices adj to v0; - for(x.f = pos.V(0)->VFp(), x.z = pos.V(0)->VFi(); x.f!=0; ++x ) { - x.f->V1(x.z)->Flags() &= NOTALLADJ; - x.f->V2(x.z)->Flags() &= NOTALLADJ; - } - // Clear visited flag for all vertices adj to v1 and set them adj1 to v1; - for(x.f = pos.V(1)->VFp(), x.z = pos.V(1)->VFi(); x.f!=0; ++x ) { - x.f->V1(x.z)->Flags() &= NOTALLADJ1; - x.f->V2(x.z)->Flags() &= NOTALLADJ1; - } - // Mark vertices adj to v1 as ADJ_1 and adj1 to v1; - for(x.f = pos.V(1)->VFp(), x.z = pos.V(1)->VFi(); x.f!=0; ++x ) { - if(x.f->V1(x.z)==pos.V(0)) x.f->V2(x.z)->Flags() |= ADJ_E | ADJ_1; - else x.f->V2(x.z)->Flags() |= ADJ_1; - if(x.f->V2(x.z)==pos.V(0)) x.f->V1(x.z)->Flags() |= ADJ_E | ADJ_1; - else x.f->V1(x.z)->Flags() |= ADJ_1; - } - - // compute the number of: - int adj01=0; // vertices adjacents to both v0 and v1 - int adje=0; // vertices adjacents to an egde (usually 2) - for(x.f = pos.V(0)->VFp(), x.z = pos.V(0)->VFi(); x.f!=0; ++x ) { - if(!x.f->V1(x.z)->IsV()) { - x.f->V1(x.z)->SetV(); - if(x.f->V1(x.z)->Flags()&ADJ_1) ++adj01; - if(x.f->V1(x.z)->Flags()&ADJ_E) ++adje; - } - if(!x.f->V2(x.z)->IsV()) { - x.f->V2(x.z)->SetV(); - if(x.f->V2(x.z)->Flags()&ADJ_1) ++adj01; - if(x.f->V2(x.z)->Flags()&ADJ_E) ++adje; - } - } - - //bool val=TopoCheck2(); - //if(val != (adj01==adje)) printf("Wrong topo %i %i\n",adj01,adje); - TriMeshType::VertexType::DeleteBitFlag(ADJ_E); - TriMeshType::VertexType::DeleteBitFlag(ADJ_1); - - return (adj01==adje); - } - - - - int DoCollapse(TriMeshType &m, EdgeType & c, const Point3 &p) - { - FindSets(c); - typename VFIVec::iterator i; - int n_face_del =0 ; - - //set Face Face topology - if (TriMeshType::HasFFTopology()) - { - //int e0=c.z; - //int e1=c.f->FFi(c.z); //opposite edge - - //FaceType *f0=c.f; - //FaceType *f1=f0->FFp(c.z); - // - ////take right indexes - //FaceType *f00=f0->FFp((e0+1)%3); - //FaceType *f01=f0->FFp((e0+2)%3); - //int If00=f0->FFi((e0+1)%3); - //int If01=f0->FFi((e0+2)%3); - // - ////then attach faces - //f00->FFp(If00)=f01; - //f00->FFi(If00)=If01; - //f01->FFp(If01)=f00; - //f01->FFi(If01)=If00; - - ////and the ones of face f1 - - //f00=f1->FFp((e1+1)%3); - //f01=f1->FFp((e1+2)%3); - //If00=f1->FFi((e1+1)%3); - //If01=f1->FFi((e1+2)%3); - // - ////and attach faces - //f00->FFp(If00)=f01; - //f00->FFi(If00)=If01; - //f01->FFp(If01)=f00; - //f01->FFi(If01)=If00; - } - - for(i=AV01().begin();i!=AV01().end();++i) - { - FaceType & f = *((*i).f); - assert(f.V((*i).z) == c.V(0)); - vcg::face::VFDetach(f,((*i).z+1)%3); - vcg::face::VFDetach(f,((*i).z+2)%3); - Allocator::DeleteFace(m,f); - //n_face_del++; - } - - //set Vertex Face topology - for(i=AV0().begin();i!=AV0().end();++i) - { - (*i).f->V((*i).z) = c.V(1); // In tutte le facce incidenti in v0, si sostituisce v0 con v1 - (*i).f->VFp((*i).z) = (*i).f->V((*i).z)->VFp(); // e appendo la lista di facce incidenti in v1 a questa faccia - (*i).f->VFi((*i).z) = (*i).f->V((*i).z)->VFi(); - (*i).f->V((*i).z)->VFp() = (*i).f; - (*i).f->V((*i).z)->VFi() = (*i).z; - } - - Allocator::DeleteVertex(m,*(c.V(0))); - //c.V(0)->SetD(); - c.V(1)->P()=p; - return n_face_del; - } - -}; - -} -} -#endif diff --git a/vcg/complex/trimesh/geodesic.h b/vcg/complex/trimesh/geodesic.h deleted file mode 100644 index 4f4adc8e..00000000 --- a/vcg/complex/trimesh/geodesic.h +++ /dev/null @@ -1,393 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ -/*#************************************************************************** - History - $Log: not supported by cvs2svn $ - Revision 1.6 2008/01/12 19:07:05 ganovelli - Recompiled from previous out of date version. Still to revise but working - - Revision 1.5 2005/12/13 17:17:19 ganovelli - first importing from old version. NOT optimized! It works with VertexFace Adjacency even over non manifolds - - - *#**************************************************************************/ - - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* -class for computing approximated geodesic distances on a mesh. - -basic example: farthest vertex from a specified one - MyMesh m; - MyMesh::VertexPointer seed,far; - MyMesh::ScalarType dist; - - vcg::Geo g; - g.FarthestVertex(m,seed,far,d); - -*/ -namespace vcg{ -namespace tri{ - -template -struct EuclideanDistance{ - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::ScalarType ScalarType; - - EuclideanDistance(){} - ScalarType operator()(const VertexType * v0, const VertexType * v1) const - {return vcg::Distance(v0->cP(),v1->cP());} -}; - -template > -class Geo{ - - public: - - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::ScalarType ScalarType; - - - - /* Auxiliary class for keeping the heap of vertices to visit and their estimated distance - */ - struct VertDist{ - VertDist(){} - VertDist(VertexPointer _v, ScalarType _d):v(_v),d(_d){} - VertexPointer v; - ScalarType d; - }; - - - /* Temporary data to associate to all the vertices: estimated distance and boolean flag - */ - struct TempData{ - TempData(){} - TempData(const ScalarType & d_){d=d_;source = NULL;} - ScalarType d; - VertexPointer source;//closest source - - }; - - typedef SimpleTempData, TempData > TempDataType; - //TempDataType * TD; - - - struct pred: public std::binary_function{ - pred(){}; - bool operator()(const VertDist& v0, const VertDist& v1) const - {return (v0.d > v1.d);} - }; - struct pred_addr: public std::binary_function{ - pred_addr(){}; - bool operator()(const VertDist& v0, const VertDist& v1) const - {return (v0.v > v1.v);} - }; - - //************** calcolo della distanza di pw in base alle distanze note di pw1 e curr - //************** sapendo che (curr,pw,pw1) e'una faccia della mesh - //************** (vedi figura in file distance.gif) - static ScalarType Distance(const VertexPointer &pw, - const VertexPointer &pw1, - const VertexPointer &curr, - const ScalarType &d_pw1, - const ScalarType &d_curr) - { - ScalarType curr_d=0; - - ScalarType ew_c = DistanceFunctor()(pw,curr); - ScalarType ew_w1 = DistanceFunctor()(pw,pw1); - ScalarType ec_w1 = DistanceFunctor()(pw1,curr); - CoordType w_c = (pw->cP()-curr->cP()).Normalize() * ew_c; - CoordType w_w1 = (pw->cP() - pw1->cP()).Normalize() * ew_w1; - CoordType w1_c = (pw1->cP() - curr->cP()).Normalize() * ec_w1; - - ScalarType alpha,alpha_, beta,beta_,theta,h,delta,s,a,b; - - alpha = acos((w_c.dot(w1_c))/(ew_c*ec_w1)); - s = (d_curr + d_pw1+ec_w1)/2; - a = s/ec_w1; - b = a*s; - alpha_ = 2*acos ( std::min(1.0,sqrt( (b- a* d_pw1)/d_curr))); - - if ( alpha+alpha_ > M_PI){ - curr_d = d_curr + ew_c; - }else - { - beta_ = 2*acos ( std::min(1.0,sqrt( (b- a* d_curr)/d_pw1))); - beta = acos((w_w1).dot(-w1_c)/(ew_w1*ec_w1)); - - if ( beta+beta_ > M_PI) - curr_d = d_pw1 + ew_w1; - else - { - theta = ScalarType(M_PI)-alpha-alpha_; - delta = cos(theta)* ew_c; - h = sin(theta)* ew_c; - curr_d = sqrt( pow(h,2)+ pow(d_curr + delta,2)); - } - } - return (curr_d); - } - - /* - starting from the seeds, it assign a distance value to each vertex. The distance of a vertex is its - approximated geodesic distance to the closest seeds. - This is function is not meant to be called (although is not prevented). Instead, it is invoked by - wrapping function. - */ - static VertexPointer Visit( - MeshType & m, - std::vector & seedVec, - ScalarType & max_distance, - bool farthestOnBorder = false, - ScalarType distance_threshold = std::numeric_limits::max(), - typename MeshType::template PerVertexAttributeHandle * sources = NULL - ) -{ - bool isLeaf; - std::vector frontier; - VertexIterator ii; - std::list children; - VertexPointer curr,farthest=0,pw1; - typename std::list::iterator is; - std::deque leaves; - std::vector _frontier; - ScalarType unreached = std::numeric_limits::max(); - - std::vector > expansion; - typename std::vector ::iterator ifr; - face::VFIterator x; - VertexPointer pw; - - //Requirements - assert(m.HasVFTopology()); - assert(!seedVec.empty()); - - TempDataType * TD; - TD = new TempDataType(m.vert,unreached); - - for(ifr = seedVec.begin(); ifr != seedVec.end(); ++ifr){ - (*TD)[(*ifr).v].d = 0.0; - (*ifr).d = 0.0; - (*TD)[(*ifr).v].source = (*ifr).v; - frontier.push_back(VertDist((*ifr).v,0.0)); - } - // initialize Heap - make_heap(frontier.begin(),frontier.end(),pred()); - - ScalarType curr_d,d_curr = 0.0,d_heap; - VertexPointer curr_s = NULL; - max_distance=0.0; - typename std::vector:: iterator iv; - - while(!frontier.empty() && max_distance < distance_threshold) - { - pop_heap(frontier.begin(),frontier.end(),pred()); - curr = (frontier.back()).v; - curr_s = (*TD)[curr].source; - if(sources!=NULL) - (*sources)[curr] = curr_s; - d_heap = (frontier.back()).d; - frontier.pop_back(); - - assert((*TD)[curr].d <= d_heap); - assert(curr_s != NULL); - if((*TD)[curr].d < d_heap )// a vertex whose distance has been improved after it was inserted in the queue - continue; - assert((*TD)[curr].d == d_heap); - - d_curr = (*TD)[curr].d; - - isLeaf = (!farthestOnBorder || curr->IsB()); - - face::VFIterator x;int k; - - for( x.f = curr->VFp(), x.z = curr->VFi(); x.f!=0; ++x ) - for(k=0;k<2;++k) - { - if(k==0) { - pw = x.f->V1(x.z); - pw1=x.f->V2(x.z); - } - else { - pw = x.f->V2(x.z); - pw1=x.f->V1(x.z); - } - - const ScalarType & d_pw1 = (*TD)[pw1].d; - { - - const ScalarType inter = DistanceFunctor()(curr,pw1);//(curr->P() - pw1->P()).Norm(); - const ScalarType tol = (inter + d_curr + d_pw1)*.0001f; - - if ( ((*TD)[pw1].source != (*TD)[curr].source)||// not the same source - (inter + d_curr < d_pw1 +tol ) || - (inter + d_pw1 < d_curr +tol ) || - (d_curr + d_pw1 < inter +tol ) // triangular inequality - ) - curr_d = d_curr + DistanceFunctor()(pw,curr);//(pw->P()-curr->P()).Norm(); - else - curr_d = Distance(pw,pw1,curr,d_pw1,d_curr); - - } - - if((*TD)[(pw)].d > curr_d){ - (*TD)[(pw)].d = curr_d; - (*TD)[pw].source = curr_s; - frontier.push_back(VertDist(pw,curr_d)); - push_heap(frontier.begin(),frontier.end(),pred()); - } - if(isLeaf){ - if(d_curr > max_distance){ - max_distance = d_curr; - farthest = curr; - } - } - } - }// end while - - // scrivi le distanze sul campo qualita' (nn: farlo parametrico) - VertexIterator vi; - for(vi = m.vert.begin(); vi != m.vert.end(); ++vi) - (*vi).Q() = (*TD)[&(*vi)].d; - - delete TD; - assert(farthest); - return farthest; - - } - - -public: - /* - Given a mesh and a vector of pointers to vertices (sources), assigns the approximated geodesic - distance from the cloasest source to all the mesh vertices and returns the pointer to the farthest. - Note: update the field Q() of the vertices - */ - static bool FarthestVertex( MeshType & m, - std::vector & fro, - VertexPointer & farthest, - ScalarType & distance, - ScalarType distance_thr = std::numeric_limits::max(), - typename MeshType::template PerVertexAttributeHandle * sources = NULL){ - - typename std::vector::iterator fi; - std::vectorfr; - if(fro.empty()) return false; - - for( fi = fro.begin(); fi != fro.end() ; ++fi) - fr.push_back(VertDist(*fi,0.0)); - farthest = Visit(m,fr,distance,false,distance_thr,sources); - return true; - } - /* - Given a mesh and a pointers to a vertex-source (source), assigns the approximated geodesic - distance from the vertex-source to all the mesh vertices and returns the pointer to the farthest - Note: update the field Q() of the vertices - */ - static void FarthestVertex( MeshType & m, - VertexPointer seed, - VertexPointer & farthest, - ScalarType & distance, - ScalarType distance_thr = std::numeric_limits::max()){ - std::vector seedVec; - seedVec.push_back( seed ); - VertexPointer v0; - FarthestVertex(m,seedVec,v0,distance,distance_thr); - farthest = v0; -} - -/* - Same as FarthestPoint but the returned pointer is to a border vertex - Note: update the field Q() of the vertices -*/ - static void FarthestBVertex(MeshType & m, - std::vector & seedVec, - VertexPointer & farthest, - ScalarType & distance, - typename MeshType::template PerVertexAttributeHandle * sources = NULL - ){ - - typename std::vector::iterator fi; - std::vectorfr; - - for( fi = seedVec.begin(); fi != seedVec.end() ; ++fi) - fr.push_back(VertDist(*fi,-1)); - farthest = Visit(m,fr,distance,true,sources); -} -/* - Same as FarthestPoint but the returned pointer is to a border vertex - Note: update the field Q() of the vertices -*/ - static void FarthestBVertex( MeshType & m, - VertexPointer seed, - VertexPointer & farthest, - ScalarType & distance, - typename MeshType::template PerVertexAttributeHandle * sources = NULL){ - std::vector fro; - fro.push_back( seed ); - VertexPointer v0; - FarthestBVertex(m,fro,v0,distance,sources); - farthest = v0; - } - -/* - Assigns to each vertex of the mesh its distance to the closest vertex on the border - Note: update the field Q() of the vertices -*/ - static bool DistanceFromBorder( MeshType & m, - ScalarType & distance, - typename MeshType::template PerVertexAttributeHandle * sources = NULL - ){ - std::vector fro; - VertexIterator vi; - VertexPointer farthest; - for(vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if( (*vi).IsB()) - fro.push_back(&(*vi)); - if(fro.empty()) return false; - - tri::UpdateQuality::VertexConstant(m,0); - - return FarthestVertex(m,fro,farthest,distance,std::numeric_limits::max(),sources); -} - - }; -};// end namespace tri -};// end namespace vcg diff --git a/vcg/complex/trimesh/halfedge_quad_clean.h b/vcg/complex/trimesh/halfedge_quad_clean.h deleted file mode 100755 index 0d2c5198..00000000 --- a/vcg/complex/trimesh/halfedge_quad_clean.h +++ /dev/null @@ -1,712 +0,0 @@ -#ifndef HALFEDGEQUADCLEAN_H -#define HALFEDGEQUADCLEAN_H - -#include -#include -#include -#include -#include -#include - - -namespace vcg -{ - namespace tri - { - /*! - * \brief The class provides methods for detecting doublets and singlets and removing them - * - */ - - template class HalfedgeQuadClean - { - - protected: - - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::EdgePointer EdgePointer; - typedef typename MeshType::HEdgePointer HEdgePointer; - typedef typename MeshType::FacePointer FacePointer; - - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::EdgeIterator EdgeIterator; - typedef typename MeshType::HEdgeIterator HEdgeIterator; - typedef typename MeshType::FaceIterator FaceIterator; - - /*! Adds to a queue all faces on the 1-ring of a given vertex - * - * \param q Queue of faces - * \param vp Pointer to the vertex - * - */ - static void add_faces(queue &q, VertexPointer vp) - { - vector faces = HalfEdgeTopology::get_incident_faces(vp); - - for(typename vector::iterator fi = faces.begin(); fi != faces.end(); ++fi) - { - if(*fi) - q.push(*fi); - } - } - - /*! Removes doublets from all the faces into a queue until the queue empties - * - * \param m Mesh - * \param faces Set of all faces modified by the removals - * \param q Queue of faces to clean - * - */ - static void remove_doublets(MeshType &m, set &faces, queue &q) - { - - while(!q.empty()) - { - FacePointer fp = q.front(); - q.pop(); - - if( !fp->IsD() ) - { - faces.insert(remove_doublet(m,fp, &q)); - } - } - } - - /*! Removes a doublet and all the other ones that the removal may have generated - * - * \param m Mesh - * \param fp Pointer to the face to clean from doublets - * \param Queue of faces to check for new doublets - * - * \return The new face generated after doublet removal - */ - static FacePointer remove_doublet(MeshType &m, FacePointer fp, queue *q = NULL) - { - vector hedges = HalfEdgeTopology::find_doublet_hedges_quad(fp); - - assert(hedges.size() <= 4); - - switch(hedges.size()) - { - // No doublets - case 0: - return NULL; - - // A single doublet - case 1: - if(q) - { - add_faces(*q, hedges[0]->HNp()->HVp()); - - add_faces(*q, hedges[0]->HPp()->HVp()); - } - - return HalfEdgeTopology::doublet_remove_quad(m, hedges[0]->HVp()); - - // Two doublets on the same face - case 2: - { - - if(q) - { - add_faces(*q, hedges[0]->HNp()->HVp()); - - add_faces(*q, hedges[0]->HPp()->HVp()); - } - - FacePointer fp1 = HalfEdgeTopology::doublet_remove_quad(m, hedges[0]->HVp()); - - // Removal of the doublet may generate a singlet - if(HalfEdgeTopology::is_singlet_quad(fp1)) - { - - HEdgePointer hp = HalfEdgeTopology::singlet_remove_quad(m, fp1); - - if(hp) - { - if(q) - { - if(hp->HFp()) - q->push(hp->HFp()); - if(hp->HOp()->HFp()) - q->push(hp->HOp()->HFp()); - } - - int valence1, valence2; - - valence1 = HalfEdgeTopology::vertex_valence(hp->HVp()); - valence2 = HalfEdgeTopology::vertex_valence(hp->HOp()->HVp()); - - // Check if the removal of the singlet generated other singlets, then iteratively remove them - while(valence1 == 1 || valence2 == 1) - { - - assert(! (valence1 == 1 && valence2 == 1)); - - FacePointer singlet_pointer; - - if(valence1 == 1 ) - singlet_pointer = hp->HFp(); - else - singlet_pointer = hp->HOp()->HFp(); - - hp = HalfEdgeTopology::singlet_remove_quad(m, singlet_pointer); - - if(!hp) - break; - - if(q) - { - if(hp->HFp()) - q->push(hp->HFp()); - if(hp->HOp()->HFp()) - q->push(hp->HOp()->HFp()); - } - - valence1 = HalfEdgeTopology::vertex_valence(hp->HVp()); - valence2 = HalfEdgeTopology::vertex_valence(hp->HOp()->HVp()); - - } - } - } - - return fp1; - } - - // Four doublets: simply remove one of the two faces - case 4: - HalfEdgeTopology::remove_face(m,fp->FHp()->HOp()->HFp()); - return fp; - - default: - assert(0); - } - } - - - - - public: - - /*! Removes doublets from all the faces on the 1-ring of the given vertices - * - * \param m Mesh - * \param Set of all faces modified by the removals - * \param vertices Vector of vertices that will be - * - */ - static void remove_doublets(MeshType &m, set &faces, vector vertices) - { - queue q; - - for(typename vector::iterator vi = vertices.begin(); vi != vertices.end(); ++vi) - { - vector inc_faces = HalfEdgeTopology::get_incident_faces(*vi); - - for(typename vector::iterator fi = inc_faces.begin(); fi != inc_faces.end(); ++fi) - { - if(*fi) - if( !((*fi)->IsD()) ) - q.push(*fi); - } - } - - remove_doublets(m, faces, q); - } - - /*! Removes doublets from all the faces on the 1-ring of the given vertices - * - * \param m Mesh - * \param vertices Vector of vertices that will be - * - */ - static void remove_doublets(MeshType &m, vector vertices) - { - set faces; - - remove_doublets(m,faces,vertices); - } - - /*! Removes doublets from a set of faces - * - * \param m Mesh - * \param set of faces to clean - * - */ - static void remove_doublets(MeshType &m, set &faces) - { - - queue q; - - for(typename set::iterator fi = faces.begin(); fi != faces.end(); ++fi) - { - if(*fi) - if( !((*fi)->IsD()) ) - q.push(*fi); - } - - remove_doublets(m, faces, q); - - } - - - /*! Removes all doublets from a mesh - * - * \param m Mesh - * - * \return Number of doublets removed - */ - static int remove_doublets(MeshType &m) - { - int count; - int removed = 0; - do - { - count = 0; - for(FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - { - if( !((*fi).IsD()) ) - { - if(remove_doublet(m, &(*fi))) - count++; - } - } - - removed += count; - - }while(count != 0); - - return removed; - } - - /*! Removes all singlets from a mesh - * - * \param m Mesh - * - * \return Number of singlets removed - */ - static int remove_singlets(MeshType &m) - { - int removed = 0; - int count; - do - { - count = 0; - for(FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - { - if( !((*fi).IsD()) ) - { - if( HalfEdgeTopology::is_singlet_quad(&(*fi)) ) - { - HalfEdgeTopology::singlet_remove_quad(m, &(*fi)); - count++; - } - } - } - - removed += count; - - }while(count != 0); - - return removed; - } - - /*! Checks if a mesh has singlets - * - * \param m Mesh - * - * \return Value indicating whether mesh has singlets - */ - static bool has_singlets(MeshType &m) - { - - for(FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - { - if( !((*fi).IsD()) ) - { - if( HalfEdgeTopology::is_singlet_quad(&(*fi)) ) - return true; - } - } - - return false; - } - - /*! Checks if a mesh has doublets - * - * \param m Mesh - * - * \return Value indicating whether mesh has doublets - */ - static bool has_doublets(MeshType &m) - { - - for(FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - { - if( !((*fi).IsD()) ) - { - if( HalfEdgeTopology::has_doublet_quad(&(*fi)) ) - return true; - } - } - - return false; - } - - /*! Performs rotation of selected edges computing the best rotation - * - * - * \param m Mesh - * \param hedges Vector of halfedges representing the edges to rotate - * \param faces Set of modified faces (every modified face will be inserted into this set) - * - */ - template - static void flip_edges(MeshType &m, vector &hedges, set &faces) - { - - for(typename vector::iterator hi = hedges.begin(); hi != hedges.end(); ++hi) - { - // edge must be shared by two faces - if((*hi)->HFp() && (*hi)->HOp()->HFp()) - { - if(!(*hi)->IsD() && !(*hi)->HFp()->IsD() && !(*hi)->HOp()->HFp()->IsD()) - { - typename PriorityType::FlipType fliptype = PriorityType::best_flip( *hi ); - - if(fliptype != PriorityType::NO_FLIP) - { - - vector vertices; - - // Record old vertices for future removal of doublets - vertices.push_back((*hi)->HVp()); - vertices.push_back((*hi)->HOp()->HVp()); - - // Add modified faces into the set of faces - faces.insert((*hi)->HFp()); - faces.insert((*hi)->HOp()->HFp()); - - bool cw = (fliptype == PriorityType::CW_FLIP); - HalfEdgeTopology::edge_rotate_quad((*hi),cw); - - // After a rotation doublets may have generated - remove_doublets(m, faces, vertices); - - } - } - } - } - } - - /*! Performs edge rotations on the entire mesh computing the best rotation for each edge - * - * - * \param m Mesh - * - */ - template - static int flip_edges(MeshType &m) - { - int count; - int ret=0; - do - { - count = 0; - for(typename MeshType::EdgeIterator ei = m.edge.begin(); ei != m.edge.end(); ++ei) - { - - if( !(ei->IsD()) ) - { - HEdgePointer hp = ei->EHp(); - - if(hp->HFp() && hp->HOp()->HFp()) - { - typename PriorityType::FlipType fliptype = PriorityType::best_flip( hp ); - - if(fliptype != PriorityType::NO_FLIP) - { - vector vertices; - - // Record old vertices for future removal of doublets - vertices.push_back(hp->HVp()); - vertices.push_back(hp->HOp()->HVp()); - - bool cw = (fliptype == PriorityType::CW_FLIP); - HalfEdgeTopology::edge_rotate_quad(hp,cw); - - // After a rotation doublets may have generated - remove_doublets(m, vertices); - - count++; - } - } - - } - } - - ret+=count; - - }while(count != 0); - - return ret; - } - - }; - - - /*! - * \brief Generic priority for edge rotations - * - */ - template class EdgeFlipPriority - { - public: - typedef typename MeshType::HEdgePointer HEdgePointer; - - /// Possible types of rotation - enum FlipType { NO_FLIP, CW_FLIP, CCW_FLIP}; - - /*! - * Computes the best rotation to perform - * - * \param hp Pointer to an halfedge representing the edge to rotate - * - * \return The best type of rotation - */ - static FlipType best_flip( HEdgePointer hp); - }; - - /*! - * \brief Priority based on maximizing vertices regularity - * - */ - template class VertReg: public EdgeFlipPriority - { - - public: - - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::EdgePointer EdgePointer; - typedef typename MeshType::HEdgePointer HEdgePointer; - typedef typename MeshType::FacePointer FacePointer; - - typedef EdgeFlipPriority Base; - typedef typename Base::FlipType FlipType; - - /// Default Constructor - VertReg(){} - - ~VertReg(){} - - /*! - * Computes the best rotation to perform for maximizing vertices regularity - * - * \param hp Pointer to an halfedge representing the edge to rotate - * - * \return The best type of rotation - */ - static FlipType best_flip( HEdgePointer hp) - { - assert(hp); - assert(!hp->IsD()); - - vector vps1 = HalfEdgeTopology::getVertices(hp->HFp(), hp); - - vector vps2 = HalfEdgeTopology::getVertices(hp->HOp()->HFp(), hp->HOp()); - - valarray valences(6); - - /* - Indices of vertices into vector valences: - - 3-------2 - | | - | f1 | - | | - 0-------1 - | | - | f2 | - | | - 4-------5 - - */ - - // Compute valencies of vertices - for(int i=0; i<4; i++) - valences[i] = HalfEdgeTopology::vertex_valence(vps1[i]) - 4 ; - - valences[4] = HalfEdgeTopology::vertex_valence(vps2[2]) - 4; - valences[5] = HalfEdgeTopology::vertex_valence(vps2[3]) - 4; - - - // Vector containing sums of the valencies in all the possible cases: no rotation, ccw rotation, cw rotation - vector sums; - - // positions: - // sums[0]: now (No rotation) - // sums[1]: flipping ccw - // sums[2]: flipping cw - - // No rotation - sums.push_back( pow(valences, 2.0).sum() ); - - // CCW - valences[0]--; - valences[1]--; - valences[2]++; - valences[4]++; - - sums.push_back( pow(valences, 2.0).sum() ); - - // CW - valences[2]--; - valences[4]--; - valences[3]++; - valences[5]++; - - sums.push_back( pow(valences, 2.0).sum() ); - - - if( sums[2]<= sums[1] && sums[2]< sums[0] ) - return Base::CW_FLIP; - - else if( sums[1]< sums[2] && sums[1]< sums[0] ) - return Base::CCW_FLIP; - - return Base::NO_FLIP; - - } - - }; - - /*! - * \brief Priority based on minimizing homeometry - * - */ - template class Homeometry: public EdgeFlipPriority - { - - public: - - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::EdgePointer EdgePointer; - typedef typename MeshType::HEdgePointer HEdgePointer; - typedef typename MeshType::FacePointer FacePointer; - - - typedef EdgeFlipPriority Base; - typedef typename Base::FlipType FlipType; - - /// Default Constructor - Homeometry(){} - - ~Homeometry(){} - - /*! - * Computes the best rotation to perform for minimizing the distance from homeometry - * - * \param hp Pointer to an halfedge representing the edge to rotate - * - * \return The best type of rotation - */ - static FlipType best_flip( HEdgePointer hp) - { - assert(hp); - assert(!hp->IsD()); - - vector face1 = HalfEdgeTopology::getVertices(hp->HFp(), hp); - vector face2 = HalfEdgeTopology::getVertices(hp->HOp()->HFp(), hp->HOp()); - - // Vector containing sums of the valencies in all the possible cases: no rotation, ccw rotation, cw rotation - vector sums; - - // positions: - // sums[0]: now (No rotation) - // sums[1]: flipping ccw - // sums[2]: flipping cw - - // No rotation - sums.push_back( distance_from_homeometry(face1, face2, 0) ); - - // CCW - face1[1] = face2[2]; - face2[1] = face1[2]; - - sums.push_back( distance_from_homeometry(face1, face2, 1) ); - - // CW - face1[2] = face2[3]; - face2[2] = face1[3]; - - sums.push_back( distance_from_homeometry(face1, face2, 2) ); - - - if( sums[2]<= sums[1] && sums[2]< sums[0] ) - return Base::CW_FLIP; - - else if( sums[1]< sums[2] && sums[1]< sums[0] ) - return Base::CCW_FLIP; - - return Base::NO_FLIP; - - } - - protected: - - /*! - * Computes the area of a quad - * - * \param vertices Vector of the four vertices of the quad - * - * \return Area of the quad - */ - static float area(vector &vertices) - { - - assert(vertices.size() == 4); - - float tri1 = Norm( (vertices[1]->cP() - vertices[0]->cP()) ^ (vertices[2]->cP() - vertices[0]->cP()) ); - float tri2 = Norm( (vertices[2]->cP() - vertices[0]->cP()) ^ (vertices[3]->cP() - vertices[0]->cP()) ); - - return (tri1+tri2) / 2; - } - - /*! - * Computes the distance of two faces from being homeometirc - * - * \param face1 Vector of vertices belonging to the first face - * \param face2 Vector of vertices belonging to the second face - * \param i Index of the edge to compute - * - * \return The computed homeometry - */ - static float distance_from_homeometry(vector &face1, vector &face2, int i) - { - // Ideal edge length - float mu = sqrt( (area(face1) + area(face2)) / 2 ); - - // Length of the i-th edge (the edge changed with a rotation) - float edge_length = Distance( face1[i]->cP(), face1[i+1]->cP() ); - - // Length of the diagonals - valarray diagonals(4); - - diagonals[0] = Distance( face1[0]->cP(), face1[2]->cP() ); - diagonals[1] = Distance( face1[1]->cP(), face1[3]->cP() ); - diagonals[2] = Distance( face2[0]->cP(), face2[2]->cP() ); - diagonals[3] = Distance( face2[1]->cP(), face2[3]->cP() ); - - // Ideal diagonal length - float ideal_diag_length = SQRT_TWO*mu; - - float sum_diagonals = pow(diagonals - ideal_diag_length, 2.0).sum(); - - return (pow (edge_length - mu , static_cast(2.0)) + sum_diagonals); - } - - }; - - } -} -#endif // HALFEDGEQUADCLEAN_H diff --git a/vcg/complex/trimesh/hole.h b/vcg/complex/trimesh/hole.h deleted file mode 100644 index 2bdd0d02..00000000 --- a/vcg/complex/trimesh/hole.h +++ /dev/null @@ -1,992 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ -/**************************************************************************** -History - -$Log: not supported by cvs2svn $ -Revision 1.34 2007/01/31 15:25:49 giec -Remove some usless code in Minimum Weight Triangulation. - -Revision 1.33 2007/01/31 11:46:12 giec -Bug fix - -Revision 1.32 2007/01/18 18:15:14 cignoni -added missing typenames - -Revision 1.31 2007/01/18 11:17:43 giec -The minimum weight algorithm keep the topology consistent. - -Revision 1.30 2007/01/10 12:07:54 giec -Bugfixed ComputeDihedralAngle function - -Revision 1.29 2006/12/27 15:09:52 giec -Bug fix on ComputeDihedralAngle function - -Revision 1.28 2006/12/12 11:14:51 cignoni -Commented some variant of the quality measure of weighted ears - -Revision 1.27 2006/12/07 00:40:18 cignoni -Added many this-> for gcc compiling - -Revision 1.26 2006/12/06 13:03:59 cignoni -Corrected bugs on selfintersection - -Revision 1.25 2006/12/06 00:12:53 cignoni -Heavily restructured and corrected. Now a single Close ear function -Corrected Hole search function, and management of double non manifold vertex in a hole -Changed priority strategy in the heap, now a mix of quality and dihedral angle. -Changed but still untested IntersectionEar - -Revision 1.24 2006/12/01 21:24:16 cignoni -Corrected bug in the search of holes. Removed output prints - -Revision 1.23 2006/12/01 08:53:55 cignoni -Corrected pop_heap vs pop_back issue in heap usage - -Revision 1.22 2006/12/01 00:11:17 cignoni -Added Callback, Corrected some spelling errors (adiacense -> adjacency). -Added Validity Check function for hole loops - -Revision 1.21 2006/11/30 11:49:20 cignoni -small gcc compiling issues - -Revision 1.20 2006/11/29 16:21:45 cignoni -Made static exposed funtions of the class - -Revision 1.19 2006/11/29 15:25:22 giec -Removed limit. - -Revision 1.18 2006/11/29 15:18:49 giec -Code refactory and bugfix. - -Revision 1.17 2006/11/24 10:42:39 mariolatronico -Now compiles on gcc under linux. - -Revision 1.16 2006/11/22 13:43:28 giec -Code refactory and added minimum weight triangolation. - -Revision 1.15 2006/11/13 10:11:38 giec -Clear some useless code - -Revision 1.14 2006/11/07 15:13:56 zifnab1974 -Necessary changes for compilation with gcc 3.4.6. Especially the hash function is a problem - -Revision 1.13 2006/11/07 11:47:11 cignoni -gcc compiling issues - -Revision 1.12 2006/11/07 07:56:43 cignoni -Added missing std:: - -Revision 1.11 2006/11/06 16:12:29 giec -Leipa ear now compute max dihedral angle. - -Revision 1.10 2006/10/31 11:30:41 ganovelli -changed access throught iterator with static call to comply 2005 compiler - -Revision 1.9 2006/10/20 07:44:45 cignoni -Added missing std:: - -Revision 1.8 2006/10/18 15:06:47 giec -New policy for compute quality in TrivialEar. -Bugfixed LeipaEar. -Added new algorithm "selfintersection" with test for self intersection. - -Revision 1.7 2006/10/10 09:12:02 giec -Bugfix and added a new type of ear (Liepa like) - -Revision 1.6 2006/10/09 10:07:07 giec -Optimized version of "EAR HOLE FILLING", the Ear is selected according to its dihedral angle. - -Revision 1.5 2006/10/06 15:28:14 giec -first working implementationof "EAR HOLE FILLING". - -Revision 1.4 2006/10/02 12:06:40 giec -BugFix - -Revision 1.3 2006/09/27 15:33:32 giec -It close one simple hole . . . - -Revision 1.2 2006/09/27 09:29:53 giec -Frist working release whit a few bugs. -It almost fills the hole ... - -Revision 1.1 2006/09/25 09:17:44 cignoni -First Non working Version - -****************************************************************************/ -#ifndef __VCG_TRI_UPDATE_HOLE -#define __VCG_TRI_UPDATE_HOLE - -#include -#include -#include -#include -#include -#include - -namespace vcg { - namespace tri { - - /* - Un ear e' identificato da due hedge pos. - i vertici dell'ear sono - e0.VFlip().v - e0.v - e1.v - Vale che e1== e0.NextB(); - e che e1.FlipV() == e0; - Situazioni ear non manifold, e degeneri (buco triangolare) - - T XXXXXXXXXXXXX A /XXXXX B en/XXXXX - /XXXXXXXXXXXXXXX /XXXXXX /XXXXXX - XXXXXXep==en XXX ep\ /en XXXX /e1 XXXX - XXXXXX ----/| XX ------ ----/| XX ------ ----/|XXX - XXXXXX| /e1 XX XXXXXX| /e1 XX XXXXXX| o/e0 XX - XXXXXX| /XXXXXX XXXXXX| /XXXXXX XXXXXX| /XXXXXX - XXX e0|o/XXXXXXX XXX e0|o/XXXXXXX XXX ep| /XXXXXXX - XXX \|/XXXXXXXX XXX \|/XXXXXXXX XXX \|/XXXXXXXX - XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX - */ - template class TrivialEar - { - public: - typedef typename MESH::FaceType FaceType; - typedef typename MESH::FacePointer FacePointer; - typedef typename face::Pos PosType; - typedef typename MESH::ScalarType ScalarType; - typedef typename MESH::CoordType CoordType; - - PosType e0; - PosType e1; - CoordType n; // the normal of the face defined by the ear - const char * Dump() {return 0;} - const CoordType &cP(int i) const {return P(i);} - const CoordType &P(int i) const { - switch(i) { - case 0 : return e0.v->cP(); - case 1 : return e1.v->cP(); - case 2 : return e0.VFlip()->cP(); - default: assert(0); - } - return e0.v->cP(); - } - - ScalarType quality; - ScalarType angle; - //std::vector* vf; - TrivialEar(){} - TrivialEar(const PosType & ep) - { - e0=ep; - assert(e0.IsBorder()); - e1=e0; - e1.NextB(); - n=vcg::Normal(*this); - ComputeQuality(); - ComputeAngle(); - } - - /// Compute the angle of the two edges of the ear. - // it tries to make the computation in a precision safe way. - // the angle computation takes into account the case of reversed ears - void ComputeAngle() - { - angle=Angle(cP(2)-cP(0), cP(1)-cP(0)); - ScalarType flipAngle = n.dot(e0.v->N()); - if(flipAngle<0) angle = (2.0 *(float)M_PI) - angle; - } - - virtual inline bool operator < ( const TrivialEar & c ) const { return quality < c.quality; } - - bool IsNull(){return e0.IsNull() || e1.IsNull();} - void SetNull(){e0.SetNull();e1.SetNull();} - virtual void ComputeQuality() { quality = QualityFace(*this) ; }; - bool IsUpToDate() {return ( e0.IsBorder() && e1.IsBorder());}; - // An ear is degenerated if both of its two endpoints are non manifold. - bool IsDegen(const int nonManifoldBit) - { - if(e0.VFlip()->IsUserBit(nonManifoldBit) && e1.V()->IsUserBit(nonManifoldBit)) - return true; - else return false; - } - bool IsConcave() const {return(angle > (float)M_PI);} - - virtual bool Close(PosType &np0, PosType &np1, FaceType * f) - { - // simple topological check - if(e0.f==e1.f) { - //printf("Avoided bad ear"); - return false; - } - - //usato per generare una delle due nuove orecchie. - PosType ep=e0; ep.FlipV(); ep.NextB(); ep.FlipV(); // he precedente a e0 - PosType en=e1; en.NextB(); // he successivo a e1 - - (*f).V(0) = e0.VFlip(); - (*f).V(1) = e0.v; - (*f).V(2) = e1.v; - ComputeNormal(*f); - - (*f).FFp(0) = e0.f; - (*f).FFi(0) = e0.z; - (*f).FFp(1) = e1.f; - (*f).FFi(1) = e1.z; - (*f).FFp(2) = f; - (*f).FFi(2) = 2; - - e0.f->FFp(e0.z)=f; - e0.f->FFi(e0.z)=0; - - e1.f->FFp(e1.z)=f; - e1.f->FFi(e1.z)=1; - - // caso ear degenere per buco triangolare - if(ep==en) - { - //printf("Closing the last triangle"); - f->FFp(2)=en.f; - f->FFi(2)=en.z; - en.f->FFp(en.z)=f; - en.f->FFi(en.z)=2; - np0.SetNull(); - np1.SetNull(); - } - // Caso ear non manifold a - else if(ep.v==en.v) - { - //printf("Ear Non manif A\n"); - PosType enold=en; - en.NextB(); - f->FFp(2)=enold.f; - f->FFi(2)=enold.z; - enold.f->FFp(enold.z)=f; - enold.f->FFi(enold.z)=2; - np0=ep; - np1=en; - } - // Caso ear non manifold b - else if(ep.VFlip()==e1.v) - { - //printf("Ear Non manif B\n"); - PosType epold=ep; - ep.FlipV(); ep.NextB(); ep.FlipV(); - f->FFp(2)=epold.f; - f->FFi(2)=epold.z; - epold.f->FFp(epold.z)=f; - epold.f->FFi(epold.z)=2; - np0=ep; // assign the two new - np1=en; // pos that denote the ears - } - else // caso standard // Now compute the new ears; - { - np0=ep; - np1=PosType(f,2,e1.v); - } - - return true; - } - }; - - //Ear with FillHoleMinimumWeight's quality policy - template class MinimumWeightEar : public TrivialEar - { - public: - static float &DiedralWeight() { static float _dw=1.0; return _dw;} - typedef TrivialEar TE; - typename MESH::ScalarType dihedralRad; - typename MESH::ScalarType aspectRatio; - const char * Dump() { - static char buf[200]; - if(this->IsConcave()) sprintf(buf,"Dihedral -(deg) %6.2f Quality %6.2f\n",math::ToDeg(dihedralRad),aspectRatio); - else sprintf(buf,"Dihedral (deg) %6.2f Quality %6.2f\n",math::ToDeg(dihedralRad),aspectRatio); - return buf; - } - - MinimumWeightEar(){} - //MinimumWeightEar(const PosType & ep) : TrivialEar(ep) - MinimumWeightEar(const typename face::Pos& ep) : TrivialEar(ep) - { - ComputeQuality(); - } - - // In the heap, by default, we retrieve the LARGEST value, - // so if we need the ear with minimal dihedral angle, we must reverse the sign of the comparison. - // The concave elements must be all in the end of the heap, sorted accordingly, - // So if only one of the two ear is Concave that one is always the minimum one. - // the pow function is here just to give a way to play with different weighting schemas, balancing in a different way - - virtual inline bool operator < ( const MinimumWeightEar & c ) const - { - if(TE::IsConcave() == c.IsConcave()) - { - return (pow((float)dihedralRad,(float)DiedralWeight())/aspectRatio) > (pow((float)c.dihedralRad,(float)DiedralWeight())/c.aspectRatio); - } - if(TE::IsConcave()) return true; - // assert(c.IsConcave()); - return false; - } - - // the real core of the whole hole filling strategy. - virtual void ComputeQuality() - { - //compute quality by (dihedral ancgle, area/sum(edge^2) ) - typename MESH::CoordType n1=TE::e0.FFlip()->cN(); - typename MESH::CoordType n2=TE::e1.FFlip()->cN(); - - dihedralRad = std::max(Angle(TE::n,n1),Angle(TE::n,n2)); - aspectRatio = QualityFace(*this); - } - - }; - //Ear for selfintersection algorithm - template class SelfIntersectionEar : public MinimumWeightEar - { - public: - typedef typename MESH::FaceType FaceType; - typedef typename MESH::FacePointer FacePointer; - typedef typename face::Pos PosType; - typedef typename MESH::ScalarType ScalarType; - typedef typename MESH::CoordType CoordType; - - static std::vector &AdjacencyRing() - { - static std::vector ar; - return ar; - } - - SelfIntersectionEar(){} - SelfIntersectionEar(const PosType & ep):MinimumWeightEar(ep){} - - virtual bool Close(PosType &np0, PosType &np1, FacePointer f) - { - PosType ep=this->e0; ep.FlipV(); ep.NextB(); ep.FlipV(); // he precedente a e0 - PosType en=this->e1; en.NextB(); // he successivo a e1 - //costruisco la faccia e poi testo, o copio o butto via. - (*f).V(0) = this->e0.VFlip(); - (*f).V(1) = this->e0.v; - (*f).V(2) = this->e1.v; - - (*f).FFp(0) = this->e0.f; - (*f).FFi(0) = this->e0.z; - (*f).FFp(1) = this->e1.f; - (*f).FFi(1) = this->e1.z; - (*f).FFp(2) = f; - (*f).FFi(2) = 2; - - int a1, a2; - a1= this->e0.z; - a2= this->e1.z; - - this->e0.f->FFp(this->e0.z)=f; - this->e0.f->FFi(this->e0.z)=0; - - this->e1.f->FFp(this->e1.z)=f; - this->e1.f->FFi(this->e1.z)=1; - typename std::vector< FacePointer >::iterator it; - for(it = this->AdjacencyRing().begin();it!= this->AdjacencyRing().end();++it) - { - if(!(*it)->IsD()) - if( tri::Clean::TestIntersection(&(*f),*it)) - { - this->e0.f->FFp(this->e0.z)= this->e0.f; - this->e0.f->FFi(this->e0.z)=a1; - - this->e1.f->FFp(this->e1.z)= this->e1.f; - this->e1.f->FFi(this->e1.z)=a2; - return false; - } - } - //return ((TrivialEar *)this)->Close(np0,np1,f); - this->e0.f->FFp(this->e0.z)= this->e0.f; - this->e0.f->FFi(this->e0.z)=a1; - - this->e1.f->FFp(this->e1.z)=this->e1.f; - this->e1.f->FFi(this->e1.z)=a2; - - bool ret=TrivialEar::Close(np0,np1,f); - if(ret) AdjacencyRing().push_back(f); - return ret; - } - }; - - // Funzione principale per chiudier un buco in maniera topologicamente corretta. - // Gestisce situazioni non manifold ragionevoli - // (tutte eccetto quelle piu' di 2 facce per 1 edge). - // Controlla che non si generino nuove situazioni non manifold chiudendo orecchie - // che sottendono un edge che gia'esiste. - -template -class Hole -{ -public: - typedef typename MESH::VertexType VertexType; - typedef typename MESH::VertexPointer VertexPointer; - typedef typename MESH::ScalarType ScalarType; - typedef typename MESH::FaceType FaceType; - typedef typename MESH::FacePointer FacePointer; - typedef typename MESH::FaceIterator FaceIterator; - typedef typename MESH::CoordType CoordType; - typedef typename vcg::Box3 Box3Type; - typedef typename face::Pos PosType; - -public: - - class Info - { - public: - Info(){} - Info(PosType const &pHole, int const pHoleSize, Box3 &pHoleBB) - { - p=pHole; - size=pHoleSize; - bb=pHoleBB; - } - - PosType p; - int size; - Box3Type bb; - - bool operator < (const Info & hh) const {return size < hh.size;} - - ScalarType Perimeter() - { - ScalarType sum=0; - PosType ip = p; - do - { - sum+=Distance(ip.v->cP(),ip.VFlip()->cP()); - ip.NextB(); - } - while (ip != p); - return sum; - } - - // Support function to test the validity of a single hole loop - // for now it test only that all the edges are border; - // The real test should check if all non manifold vertices - // are touched only by edges belonging to this hole loop. - bool CheckValidity() - { - if(!p.IsBorder()) - return false; - PosType ip=p;ip.NextB(); - for(;ip!=p;ip.NextB()) - { - if(!ip.IsBorder()) - return false; - } - return true; - } - }; - -template - static void FillHoleEar(MESH &m, Info &h ,int UBIT, std::vector &app,std::vector *vf =0) - { - //Aggiungo le facce e aggiorno il puntatore alla faccia! - FaceIterator f = tri::Allocator::AddFaces(m, h.size-2, app); - assert(h.p.f >= &*m.face.begin()); - assert(h.p.f <= &m.face.back()); - assert(h.p.IsBorder());//test fondamentale altrimenti qualcosa s'e' rotto! - std::vector< EAR > H; - H.reserve(h.size); - int nmBit= VertexType::NewBitFlag(); // non manifoldness bit - - //First loops around the hole to mark non manifold vertices. - PosType ip = h.p; // Pos iterator - do{ - ip.V()->ClearUserBit(nmBit); - ip.V()->ClearV(); - ip.NextB(); - } while(ip!=h.p); - - ip = h.p; // Re init the pos iterator for another loop (useless if everithing is ok!!) - do{ - if(!ip.V()->IsV()) - ip.V()->SetV(); // All the vertexes that are visited more than once are non manifold - else ip.V()->SetUserBit(nmBit); - ip.NextB(); - } while(ip!=h.p); - - PosType fp = h.p; - do{ - EAR app = EAR(fp); - H.push_back( app ); - //printf("Adding ear %s ",app.Dump()); - fp.NextB(); - assert(fp.IsBorder()); - }while(fp!=h.p); - - int cnt=h.size; - - make_heap(H.begin(), H.end()); - - //finche' il buco non e' chiuso o non ci sono piu' orecchie da analizzare. - while( cnt > 2 && !H.empty() ) - { - //printf("Front of the heap is %s", H.front().Dump()); - pop_heap(H.begin(), H.end()); // retrieve the MAXIMUM value and put in the back; - PosType ep0,ep1; - EAR BestEar=H.back(); - H.pop_back(); - if(BestEar.IsUpToDate() && !BestEar.IsDegen(nmBit)) - { - if((*f).HasPolyInfo()) (*f).Alloc(3); - if(BestEar.Close(ep0,ep1,&*f)) - { - if(!ep0.IsNull()){ - H.push_back(EAR(ep0)); - push_heap( H.begin(), H.end()); - } - if(!ep1.IsNull()){ - H.push_back(EAR(ep1)); - push_heap( H.begin(), H.end()); - } - --cnt; - f->SetUserBit(UBIT); - if(vf != 0) (*vf).push_back(*f); - ++f; - } - }//is update() - }//fine del while principale. - //tolgo le facce non utilizzate. - while(f!=m.face.end()) - { - (*f).SetD(); - ++f; - m.fn--; - } - - VertexType::DeleteBitFlag(nmBit); // non manifoldness bit - } - - template - static int EarCuttingFill(MESH &m, int sizeHole,bool Selected = false, CallBackPos *cb=0) - { - std::vector< Info > vinfo; - int UBIT = GetInfo(m, Selected,vinfo); - - typename std::vector::iterator ith; - //Info app; - int indCb=0; - int holeCnt=0; - std::vector vfp; - for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith) - vfp.push_back( &(*ith).p.f ); - - for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith) - { - indCb++; - if(cb) (*cb)(indCb*10/vinfo.size(),"Closing Holes"); - if((*ith).size < sizeHole){ - holeCnt++; - FillHoleEar< EAR >(m, *ith,UBIT,vfp); - } - } - - FaceIterator fi; - for(fi = m.face.begin(); fi!=m.face.end(); ++fi) - { - if(!(*fi).IsD()) - (*fi).ClearUserBit(UBIT); - } - return holeCnt; - } - -// it returns the number of created holes. - -template - static int EarCuttingIntersectionFill(MESH &m, int sizeHole, bool Selected = false, CallBackPos *cb=0) - { - std::vector vinfo; - int UBIT = GetInfo(m, Selected,vinfo); - std::vector vf; - PosType sp; - PosType ap; - typename std::vector::iterator ith; - - // collect the face pointer that has to be updated by the various addfaces - std::vector vfpOrig; - for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith) - vfpOrig.push_back( &(*ith).p.f ); - - int indCb=0; - int holeCnt=0; - for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith) - { - indCb++; - if(cb) (*cb)(indCb*10/vinfo.size(),"Closing Holes"); - if((*ith).size < sizeHole){ - std::vector vfp; - holeCnt++; - vfp=vfpOrig; - EAR::AdjacencyRing().clear(); - //Loops around the hole to collect the races . - PosType ip = (*ith).p; - do - { - PosType inp = ip; - do - { - inp.FlipE(); - inp.FlipF(); - EAR::AdjacencyRing().push_back(inp.f); - } while(!inp.IsBorder()); - ip.NextB(); - }while(ip != (*ith).p); - - typename std::vector::iterator fpi; - for(fpi=EAR::AdjacencyRing().begin();fpi!=EAR::AdjacencyRing().end();++fpi) - vfp.push_back( &*fpi ); - - FillHoleEar(m, *ith,UBIT,vfp,&vf); - EAR::AdjacencyRing().clear(); - } - } - FaceIterator fi; - for(fi = m.face.begin(); fi!=m.face.end(); ++fi) - { - if(!(*fi).IsD()) - (*fi).ClearUserBit(UBIT); - } - return holeCnt; - } - - - - static int GetInfo(MESH &m,bool Selected ,std::vector& VHI) - { - FaceIterator fi; - int UBIT = FaceType::LastBitFlag(); - - for(fi = m.face.begin(); fi!=m.face.end(); ++fi) - { - if(!(*fi).IsD()) - { - if(Selected && !(*fi).IsS()) - { - //se devo considerare solo i triangoli selezionati e - //quello che sto considerando non lo e' lo marchio e vado avanti - (*fi).SetUserBit(UBIT); - } - else - { - for(int j =0; j<3 ; ++j) - { - if( face::IsBorder(*fi,j) && !(*fi).IsUserBit(UBIT) ) - {//Trovato una faccia di bordo non ancora visitata. - (*fi).SetUserBit(UBIT); - PosType sp(&*fi, j, (*fi).V(j)); - PosType fp=sp; - int holesize=0; - - Box3Type hbox; - hbox.Add(sp.v->cP()); - //printf("Looping %i : (face %i edge %i) \n", VHI.size(),sp.f-&*m.face.begin(),sp.z); - sp.f->SetUserBit(UBIT); - do - { - sp.f->SetUserBit(UBIT); - hbox.Add(sp.v->cP()); - ++holesize; - sp.NextB(); - sp.f->SetUserBit(UBIT); - assert(sp.IsBorder()); - }while(sp != fp); - - //ho recuperato l'inofrmazione su tutto il buco - VHI.push_back( Info(sp,holesize,hbox) ); - } - }//for sugli edge del triangolo - }//S & !S - }//!IsD() - }//for principale!!! - return UBIT; - } - - //Minimum Weight Algorithm - class Weight - { - public: - - Weight() { ang = 180; ar = FLT_MAX ;} - Weight( float An, float Ar ) { ang=An ; ar= Ar;} - ~Weight() {} - - float angle() const { return ang; } - float area() const { return ar; } - - Weight operator+( const Weight & other ) const {return Weight( std::max( angle(), other.angle() ), area() + other.area());} - bool operator<( const Weight & rhs ) const {return ( angle() < rhs.angle() ||(angle() == rhs.angle() && area() < rhs.area())); } - - private: - float ang; - float ar; - }; - - /* - \ / \/ - v1*---------*v4 - / \ / - / \ / - / \ / - /ear \ / -*---------*- -| v3 v2\ -*/ - - static float ComputeDihedralAngle(CoordType p1,CoordType p2,CoordType p3,CoordType p4) - { - CoordType n1 = NormalizedNormal(p1,p3,p2); - CoordType n2 = NormalizedNormal(p1,p2,p4); - return math::ToDeg(AngleN(n1,n2)); - } - - static bool existEdge(PosType pi,PosType pf) - { - PosType app = pi; - PosType appF = pi; - PosType tmp; - assert(pi.IsBorder()); - appF.NextB(); - appF.FlipV(); - do - { - tmp = app; - tmp.FlipV(); - if(tmp.v == pf.v) - return true; - app.FlipE(); - app.FlipF(); - - if(app == pi)return false; - }while(app != appF); - return false; - } - - static Weight computeWeight( int i, int j, int k, - std::vector pv, - std::vector< std::vector< int > > v) - { - PosType pi = pv[i]; - PosType pj = pv[j]; - PosType pk = pv[k]; - - //test complex edge - if(existEdge(pi,pj) || existEdge(pj,pk)|| existEdge(pk,pi) ) - { - return Weight(); - } - // Return an infinite weight, if one of the neighboring patches - // could not be created. - if(v[i][j] == -1){return Weight();} - if(v[j][k] == -1){return Weight();} - - //calcolo il massimo angolo diedrale, se esiste. - float angle = 0.0f; - PosType px; - if(i + 1 == j) - { - px = pj; - px.FlipE(); px.FlipV(); - angle = std::max(angle , ComputeDihedralAngle(pi.v->P(), pj.v->P(), pk.v->P(), px.v->P()) ); - } - else - { - angle = std::max( angle, ComputeDihedralAngle(pi.v->P(),pj.v->P(), pk.v->P(), pv[ v[i][j] ].v->P())); - } - - if(j + 1 == k) - { - px = pk; - px.FlipE(); px.FlipV(); - angle = std::max(angle , ComputeDihedralAngle(pj.v->P(), pk.v->P(), pi.v->P(), px.v->P()) ); - } - else - { - angle = std::max( angle, ComputeDihedralAngle(pj.v->P(),pk.v->P(), pi.v->P(), pv[ v[j][k] ].v->P())); - } - - if( i == 0 && k == (int)v.size() - 1) - { - px = pi; - px.FlipE(); px.FlipV(); - angle = std::max(angle , ComputeDihedralAngle(pk.v->P(), pi.v->P(), pj.v->P(),px.v->P() ) ); - } - - ScalarType area = ( (pj.v->P() - pi.v->P()) ^ (pk.v->P() - pi.v->P()) ).Norm() * 0.5; - - return Weight(angle, area); - } - - static void calculateMinimumWeightTriangulation(MESH &m, FaceIterator f,std::vector vv ) - { - std::vector< std::vector< Weight > > w; //matrice dei pesi minimali di ogni orecchio preso in conzideraione - std::vector< std::vector< int > > vi;//memorizza l'indice del terzo vertice del triangolo - - //hole size - int nv = vv.size(); - - w.clear(); - w.resize( nv, std::vector( nv, Weight() ) ); - - vi.resize( nv, std::vector( nv, 0 ) ); - - //inizializzo tutti i pesi possibili del buco - for ( int i = 0; i < nv-1; ++i ) - w[i][i+1] = Weight( 0, 0 ); - - //doppio ciclo for per calcolare di tutti i possibili triangoli i loro pesi. - for ( int j = 2; j < nv; ++j ) - { - for ( int i = 0; i + j < nv; ++i ) - { - //per ogni triangolazione mi mantengo il minimo valore del peso tra i triangoli possibili - Weight minval; - - //indice del vertice che da il peso minimo nella triangolazione corrente - int minIndex = -1; - - //ciclo tra i vertici in mezzo a i due prefissati - for ( int m = i + 1; m < i + j; ++m ) - { - Weight a = w[i][m]; - Weight b = w[m][i+j]; - Weight newval = a + b + computeWeight( i, m, i+j, vv, vi); - if ( newval < minval ) - { - minval = newval; - minIndex = m; - } - } - w[i][i+j] = minval; - vi[i][i+j] = minIndex; - } - } - - //Triangulate - int i, j; - i=0; j=nv-1; - - triangulate(m,f, i, j, vi, vv); - - while(f!=m.face.end()) - { - (*f).SetD(); - ++f; - m.fn--; - } - } - - - static void triangulate(MESH &m, FaceIterator &f,int i, int j, - std::vector< std::vector > vi, std::vector vv) - { - if(i + 1 == j){return;} - if(i==j)return; - - int k = vi[i][j]; - - if(k == -1) return; - - //Setto i vertici - f->V(0) = vv[i].v; - f->V(1) = vv[k].v; - f->V(2) = vv[j].v; - - f++; - triangulate(m,f,i,k,vi,vv); - triangulate(m,f,k,j,vi,vv); - } - - static void MinimumWeightFill(MESH &m, int holeSize, bool Selected) - { - FaceIterator fi; - std::vector vvi; - std::vector vfp; - - std::vector vinfo; - typename std::vector::iterator VIT; - GetInfo(m, Selected,vinfo); - - for(VIT = vinfo.begin(); VIT != vinfo.end();++VIT) - { - vvi.push_back(VIT->p); - } - - typename std::vector::iterator ith; - typename std::vector::iterator ithn; - typename std::vector::iterator itf; - - std::vector app; - PosType ps; - std::vector tr; - std::vector vf; - - for(ith = vvi.begin(); ith!= vvi.end(); ++ith) - { - tr.clear(); - vf.clear(); - app.clear(); - vfp.clear(); - - ps = *ith; - getBoundHole(ps,app); - - if(app.size() <= size_t(holeSize) ) - { - typename std::vector::iterator itP; - std::vector vfp; - - for(ithn = vvi.begin(); ithn!= vvi.end(); ++ithn) - vfp.push_back(&(ithn->f)); - - for(itP = app.begin (); itP != app.end ();++itP) - vfp.push_back( &(*itP).f ); - - //aggiungo le facce - FaceIterator f = tri::Allocator::AddFaces(m, (app.size()-2) , vfp); - - calculateMinimumWeightTriangulation(m,f, app); - } - } - - } - - static void getBoundHole (PosType sp,std::vector&ret) - { - PosType fp = sp; - //take vertex around the hole - do - { - assert(fp.IsBorder()); - ret.push_back(fp); - fp.NextB(); - }while(sp != fp); - } - -};//close class Hole - - } // end namespace -} -#endif diff --git a/vcg/complex/trimesh/inertia.h b/vcg/complex/trimesh/inertia.h deleted file mode 100644 index d4841bef..00000000 --- a/vcg/complex/trimesh/inertia.h +++ /dev/null @@ -1,383 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2005 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ -/**************************************************************************** -History - -$Log: not supported by cvs2svn $ -Revision 1.3 2006/03/29 10:12:08 corsini -Add cast to avoid warning - -Revision 1.2 2005/12/12 12:08:30 cignoni -First working version - -Revision 1.1 2005/11/21 15:58:12 cignoni -First Release (not working!) - - -Revision 1.13 2005/11/17 00:42:03 cignoni -****************************************************************************/ -#ifndef _VCG_INERTIA_ -#define _VCG_INERTIA_ - -/* -The algorithm is based on a three step reduction of the volume integrals -to successively simpler integrals. The algorithm is designed to minimize -the numerical errors that can result from poorly conditioned alignment of -polyhedral faces. It is also designed for efficiency. All required volume -integrals of a polyhedron are computed together during a single walk over -the boundary of the polyhedron; exploiting common subexpressions reduces -floating point operations. - -For more information, check out: - -Brian Mirtich, -``Fast and Accurate Computation of Polyhedral Mass Properties,'' -journal of graphics tools, volume 1, number 2, 1996 - -*/ - -#include -#include - -#include -namespace vcg -{ - namespace tri - { -template -class Inertia -{ - typedef InertiaMeshType MeshType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::FacePointer FacePointer; - typedef typename MeshType::FaceIterator FaceIterator; - typedef typename MeshType::ConstFaceIterator ConstFaceIterator; - typedef typename MeshType::FaceContainer FaceContainer; - typedef typename MeshType::CoordType CoordType; - -private : - enum {X=0,Y=1,Z=2}; - inline ScalarType SQR(ScalarType &x) const { return x*x;} - inline ScalarType CUBE(ScalarType &x) const { return x*x*x;} - - int A; /* alpha */ - int B; /* beta */ - int C; /* gamma */ - -/* projection integrals */ - double P1, Pa, Pb, Paa, Pab, Pbb, Paaa, Paab, Pabb, Pbbb; - -/* face integrals */ - double Fa, Fb, Fc, Faa, Fbb, Fcc, Faaa, Fbbb, Fccc, Faab, Fbbc, Fcca; - -/* volume integrals */ - double T0, T1[3], T2[3], TP[3]; - -public: - -/* compute various integrations over projection of face */ - void compProjectionIntegrals(FaceType &f) -{ - double a0, a1, da; - double b0, b1, db; - double a0_2, a0_3, a0_4, b0_2, b0_3, b0_4; - double a1_2, a1_3, b1_2, b1_3; - double C1, Ca, Caa, Caaa, Cb, Cbb, Cbbb; - double Cab, Kab, Caab, Kaab, Cabb, Kabb; - int i; - - P1 = Pa = Pb = Paa = Pab = Pbb = Paaa = Paab = Pabb = Pbbb = 0.0; - - for (i = 0; i < 3; i++) { - a0 = f.V(i)->P()[A]; - b0 = f.V(i)->P()[B]; - a1 = f.V1(i)->P()[A]; - b1 = f.V1(i)->P()[B]; - da = a1 - a0; - db = b1 - b0; - a0_2 = a0 * a0; a0_3 = a0_2 * a0; a0_4 = a0_3 * a0; - b0_2 = b0 * b0; b0_3 = b0_2 * b0; b0_4 = b0_3 * b0; - a1_2 = a1 * a1; a1_3 = a1_2 * a1; - b1_2 = b1 * b1; b1_3 = b1_2 * b1; - - C1 = a1 + a0; - Ca = a1*C1 + a0_2; Caa = a1*Ca + a0_3; Caaa = a1*Caa + a0_4; - Cb = b1*(b1 + b0) + b0_2; Cbb = b1*Cb + b0_3; Cbbb = b1*Cbb + b0_4; - Cab = 3*a1_2 + 2*a1*a0 + a0_2; Kab = a1_2 + 2*a1*a0 + 3*a0_2; - Caab = a0*Cab + 4*a1_3; Kaab = a1*Kab + 4*a0_3; - Cabb = 4*b1_3 + 3*b1_2*b0 + 2*b1*b0_2 + b0_3; - Kabb = b1_3 + 2*b1_2*b0 + 3*b1*b0_2 + 4*b0_3; - - P1 += db*C1; - Pa += db*Ca; - Paa += db*Caa; - Paaa += db*Caaa; - Pb += da*Cb; - Pbb += da*Cbb; - Pbbb += da*Cbbb; - Pab += db*(b1*Cab + b0*Kab); - Paab += db*(b1*Caab + b0*Kaab); - Pabb += da*(a1*Cabb + a0*Kabb); - } - - P1 /= 2.0; - Pa /= 6.0; - Paa /= 12.0; - Paaa /= 20.0; - Pb /= -6.0; - Pbb /= -12.0; - Pbbb /= -20.0; - Pab /= 24.0; - Paab /= 60.0; - Pabb /= -60.0; -} - - -void CompFaceIntegrals(FaceType &f) -{ - Point3 n; - ScalarType w; - double k1, k2, k3, k4; - - compProjectionIntegrals(f); - - n = f.N(); - w = -f.V(0)->P()*n; - k1 = 1 / n[C]; k2 = k1 * k1; k3 = k2 * k1; k4 = k3 * k1; - - Fa = k1 * Pa; - Fb = k1 * Pb; - Fc = -k2 * (n[A]*Pa + n[B]*Pb + w*P1); - - Faa = k1 * Paa; - Fbb = k1 * Pbb; - Fcc = k3 * (SQR(n[A])*Paa + 2*n[A]*n[B]*Pab + SQR(n[B])*Pbb - + w*(2*(n[A]*Pa + n[B]*Pb) + w*P1)); - - Faaa = k1 * Paaa; - Fbbb = k1 * Pbbb; - Fccc = -k4 * (CUBE(n[A])*Paaa + 3*SQR(n[A])*n[B]*Paab - + 3*n[A]*SQR(n[B])*Pabb + CUBE(n[B])*Pbbb - + 3*w*(SQR(n[A])*Paa + 2*n[A]*n[B]*Pab + SQR(n[B])*Pbb) - + w*w*(3*(n[A]*Pa + n[B]*Pb) + w*P1)); - - Faab = k1 * Paab; - Fbbc = -k2 * (n[A]*Pabb + n[B]*Pbbb + w*Pbb); - Fcca = k3 * (SQR(n[A])*Paaa + 2*n[A]*n[B]*Paab + SQR(n[B])*Pabb - + w*(2*(n[A]*Paa + n[B]*Pab) + w*Pa)); -} - - -void Compute(MeshType &m) -{ - tri::UpdateNormals::PerFaceNormalized(m); - double nx, ny, nz; - - T0 = T1[X] = T1[Y] = T1[Z] - = T2[X] = T2[Y] = T2[Z] - = TP[X] = TP[Y] = TP[Z] = 0; - FaceIterator fi; - for (fi=m.face.begin(); fi!=m.face.end();++fi) if(!(*fi).IsD()) { - FaceType &f=(*fi); - - nx = fabs(f.N()[0]); - ny = fabs(f.N()[1]); - nz = fabs(f.N()[2]); - if (nx > ny && nx > nz) C = X; - else C = (ny > nz) ? Y : Z; - A = (C + 1) % 3; - B = (A + 1) % 3; - - CompFaceIntegrals(f); - - T0 += f.N()[X] * ((A == X) ? Fa : ((B == X) ? Fb : Fc)); - - T1[A] += f.N()[A] * Faa; - T1[B] += f.N()[B] * Fbb; - T1[C] += f.N()[C] * Fcc; - T2[A] += f.N()[A] * Faaa; - T2[B] += f.N()[B] * Fbbb; - T2[C] += f.N()[C] * Fccc; - TP[A] += f.N()[A] * Faab; - TP[B] += f.N()[B] * Fbbc; - TP[C] += f.N()[C] * Fcca; - } - - T1[X] /= 2; T1[Y] /= 2; T1[Z] /= 2; - T2[X] /= 3; T2[Y] /= 3; T2[Z] /= 3; - TP[X] /= 2; TP[Y] /= 2; TP[Z] /= 2; -} - -ScalarType Mass() -{ - return static_cast(T0); -} - -Point3 CenterOfMass() -{ - Point3 r; - r[X] = T1[X] / T0; - r[Y] = T1[Y] / T0; - r[Z] = T1[Z] / T0; - return r; -} -void InertiaTensor(Matrix33 &J ){ - Point3 r; - r[X] = T1[X] / T0; - r[Y] = T1[Y] / T0; - r[Z] = T1[Z] / T0; - /* compute inertia tensor */ - J[X][X] = (T2[Y] + T2[Z]); - J[Y][Y] = (T2[Z] + T2[X]); - J[Z][Z] = (T2[X] + T2[Y]); - J[X][Y] = J[Y][X] = - TP[X]; - J[Y][Z] = J[Z][Y] = - TP[Y]; - J[Z][X] = J[X][Z] = - TP[Z]; - - J[X][X] -= T0 * (r[Y]*r[Y] + r[Z]*r[Z]); - J[Y][Y] -= T0 * (r[Z]*r[Z] + r[X]*r[X]); - J[Z][Z] -= T0 * (r[X]*r[X] + r[Y]*r[Y]); - J[X][Y] = J[Y][X] += T0 * r[X] * r[Y]; - J[Y][Z] = J[Z][Y] += T0 * r[Y] * r[Z]; - J[Z][X] = J[X][Z] += T0 * r[Z] * r[X]; -} - -void InertiaTensor(Matrix44 &J ) -{ - J.SetIdentity(); - Point3 r; - r[X] = T1[X] / T0; - r[Y] = T1[Y] / T0; - r[Z] = T1[Z] / T0; - /* compute inertia tensor */ - J[X][X] = (T2[Y] + T2[Z]); - J[Y][Y] = (T2[Z] + T2[X]); - J[Z][Z] = (T2[X] + T2[Y]); - J[X][Y] = J[Y][X] = - TP[X]; - J[Y][Z] = J[Z][Y] = - TP[Y]; - J[Z][X] = J[X][Z] = - TP[Z]; - - J[X][X] -= T0 * (r[Y]*r[Y] + r[Z]*r[Z]); - J[Y][Y] -= T0 * (r[Z]*r[Z] + r[X]*r[X]); - J[Z][Z] -= T0 * (r[X]*r[X] + r[Y]*r[Y]); - J[X][Y] = J[Y][X] += T0 * r[X] * r[Y]; - J[Y][Z] = J[Z][Y] += T0 * r[Y] * r[Z]; - J[Z][X] = J[X][Z] += T0 * r[Z] * r[X]; -} - - -/** Compute eigenvalues and eigenvectors of inertia tensor. - The eigenvectors make a rotation matrix that aligns the mesh along the axes of min/max inertia - */ -void InertiaTensorEigen(Matrix44 &EV, Point4 &ev ) -{ - Matrix44 it; - InertiaTensor(it); - Matrix44d EVd,ITd;ITd.Import(it); - Point4d evd; - int n; - Jacobi(ITd,evd,EVd,n); - EV.Import(EVd); - ev.Import(evd); -} - -/** Compute covariance matrix of a mesh, i.e. the integral - int_{M} { (x-b)(x-b)^T }dx where b is the barycenter and x spans over the mesh M - */ -static void Covariance(const MeshType & m, vcg::Point3 & bary, vcg::Matrix33 &C){ - // find the barycenter - - ConstFaceIterator fi; - ScalarType area = 0.0; - bary.SetZero(); - for(fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - { - bary += vcg::Barycenter( *fi )* vcg::DoubleArea(*fi); - area+=vcg::DoubleArea(*fi); - } - bary/=area; - - - C.SetZero(); - // C as covariance of triangle (0,0,0)(1,0,0)(0,1,0) - vcg::Matrix33 C0; - C0.SetZero(); - C0[0][0] = C0[1][1] = 2.0; - C0[0][1] = C0[1][0] = 1.0; - C0*=1/24.0; - - // integral of (x,y,0) in the same triangle - CoordType X(1/6.0,1/6.0,0); - vcg::Matrix33 A, // matrix that bring the vertices to (v1-v0,v2-v0,n) - DC; - for(fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - { - const CoordType &P0 = (*fi).P(0); - const CoordType &P1 = (*fi).P(1); - const CoordType &P2 = (*fi).P(2); - CoordType n = ((P1-P0)^(P2-P0)); - const float da = n.Norm(); - n/=da*da; - - #ifndef VCG_USE_EIGEN - A.SetColumn(0, P1-P0); - A.SetColumn(1, P2-P0); - A.SetColumn(2, n); - #else - A.col(0) = P1-P0; - A.col(1) = P2-P0; - A.col(2) = n; - #endif - CoordType delta = P0 - bary; - - /* DC is calculated as integral of (A*x+delta) * (A*x+delta)^T over the triangle, - where delta = v0-bary - */ - - DC.SetZero(); - DC+= A*C0*A.transpose(); - vcg::Matrix33 tmp; - tmp.OuterProduct(A*X,delta); - DC += tmp + tmp.transpose(); - DC+= tmp; - tmp.OuterProduct(delta,delta); - DC+=tmp*0.5; -// DC*=fabs(A.Determinant()); // the determinant of A is the jacobian of the change of variables A*x+delta - DC*=da; // the determinant of A is also the double area of *fi - C+=DC; - } - -} -}; // end class Inertia - - } // end namespace tri -} // end namespace vcg - - -#endif diff --git a/vcg/complex/trimesh/inside.h b/vcg/complex/trimesh/inside.h deleted file mode 100644 index 0827cf8c..00000000 --- a/vcg/complex/trimesh/inside.h +++ /dev/null @@ -1,115 +0,0 @@ - -/**************************************************************************** -* IDOLib * -* Interactive Deformable Objects Library * -* http://idolib.sf.net * -* * -* Copyright(C) 2005 * -* Visual Computing Lab * -* ISTI - Italian National Research Council * -* * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ -/**************************************************************************** - History - -$Log: not supported by cvs2svn $ -Revision 1.3 2007/06/06 15:38:57 turini -Use the barycenter function from triangle3.h instead of -the one in face\base.h. - -Revision 1.2 2007/06/06 14:26:51 pietroni -compiling error resolved - - - -****************************************************************************/ - - - -#include -#include -#include - - -#ifndef VCG_INSIDE -#define VCG_INSIDE - - -/// This static funtion is used to see if one point is inside a triangular mesh or not... -/// First parameter is a spatial indexing structure (eg. a grid) used to perform research operation, initialized with faces of the triangular mesh of type TriMeshType - -namespace vcg { - - namespace tri { - - template - class Inside - { - - private: - - typedef typename FaceSpatialIndexing::CoordType CoordType; - typedef typename FaceSpatialIndexing::ScalarType ScalarType; - - public: - - /// Return true if the point is inside the mesh. - static bool Is_Inside( TriMeshType & m, FaceSpatialIndexing & _g_mesh, const CoordType & test ) - { - typedef typename TriMeshType::FaceType FaceType; - typedef typename TriMeshType::ScalarType ScalarType; - typedef typename TriMeshType::CoordType CoordType; - const ScalarType EPSILON = 0.000001; - /// First test if the element is inside the bounding box of the mesh. - if( !( m.bbox.IsIn(test) ) ) return false; - else - { - ScalarType dist; - CoordType Norm, ip, nearest; - FaceType *f = vcg::tri::GetClosestFace< TriMeshType, FaceSpatialIndexing >( m, _g_mesh, test, m.bbox.Diag(), dist, nearest, Norm, ip ); - assert( f != NULL ); /// Check if there is any face in the mesh - /// If the point is on the face is considered inside. - if( ( test - nearest ).Norm() <= EPSILON ) return true; - /// Check if the closest point is inside a face - if( ( ip.V(0) > EPSILON ) && ( ip.V(1) > EPSILON ) && ( ip.V(2) > EPSILON ) ) - { - /// Check if the test point is inside the mesh using the normal direction - vcg::Point3f debugn = f->N(); - if( ( f->N() * ( test - nearest ) ) < 0 ) return true; - else return false; - } - /// In this case we are not sure because hit an edge or a vertex. - /// So we use a ray that go until the barycenter of found face, then see normal value again - else - { - CoordType bary = vcg::Barycenter< FaceType >(*f); - /// Set ray : origin and direction - vcg::Ray3 r; r.Set( test, ( bary - test ) ); r.Normalize(); - FaceType *f1 = vcg::tri::DoRay< TriMeshType, FaceSpatialIndexing >( m, _g_mesh, r, m.bbox.Diag(), dist ); - assert( f1 != NULL ); - /// In this case normal direction is enough. - if( ( f1->N() * ( test - bary ) ) < 0 ) return true; - else return false; - } - - } - } - - }; // end class - } -} - -#endif \ No newline at end of file diff --git a/vcg/complex/trimesh/intersection.h b/vcg/complex/trimesh/intersection.h deleted file mode 100644 index c3982a0a..00000000 --- a/vcg/complex/trimesh/intersection.h +++ /dev/null @@ -1,470 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ -/**************************************************************************** - History - -$Log: not supported by cvs2svn $ -Revision 1.11 2007/05/02 13:25:45 zifnab1974 -only use typename when necessary - -Revision 1.10 2007/04/10 22:46:57 pietroni -- line 152 changed call intersection to IntersectionPlaneTriangle because changing in function's name - -Revision 1.9 2007/01/03 15:51:28 pietroni -added initial define and included missing files - -Revision 1.8 2006/01/19 14:06:37 spinelli -add std:: namespace... - -Revision 1.7 2005/10/03 16:18:15 spinelli -add template parameter for spatialindexing struction - -Revision 1.6 2005/05/30 09:11:20 ganovelli -header added, error in include - -Revision 1.3 2005/05/17 21:19:37 ganovelli -some std::and typename missing (CRS4) - -Revision 1.2 2005/03/08 14:42:22 ganovelli -added vcg header - - -****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef __VCGLIB_INTERSECTION_TRI_MESH -#define __VCGLIB_INTERSECTION_TRI_MESH - -namespace vcg{ - -/** \addtogroup complex */ -/*@{*/ -/** - Function computing the intersection between a grid and a plane. It returns all the cells intersected -*/ -template < typename GridType,typename ScalarType> -bool Intersect( GridType & grid,Plane3 plane, std::vector &cells){ - Point3d p,_d; - Plane3d pl; - _d.Import(plane.Direction()); - pl.SetDirection(_d); - pl.SetOffset(plane.Offset()); - for( int ax = 0; ax <3; ++ax) - { int axis = ax; - int axis0 = (axis+1)%3; - int axis1 = (axis+2)%3; - int i,j; - Point3i pi; - - Segment3 seg; - seg.P0().Import(grid.bbox.min); - seg.P1().Import(grid.bbox.min); - seg.P1()[axis] = grid.bbox.max[axis]; - - for(i = 0 ; i <= grid.siz[axis0]; ++i){ - for(j = 0 ; j <= grid.siz[axis1]; ++j) - { - seg.P0()[axis0] = grid.bbox.min[axis0]+ (i+0.01) * grid.voxel[axis0] ; - seg.P1()[axis0] = grid.bbox.min[axis0]+ (i+0.01) * grid.voxel[axis0]; - seg.P0()[axis1] = grid.bbox.min[axis1]+ (j+0.01) * grid.voxel[axis1]; - seg.P1()[axis1] = grid.bbox.min[axis1]+ (j+0.01) * grid.voxel[axis1]; - if ( IntersectionPlaneSegmentEpsilon(pl,seg,p)) - { - pi[axis] = std::min(std::max(0,(int)floor((p[axis ]-grid.bbox.min[axis])/grid.voxel[axis])),grid.siz[axis]); - pi[axis0] = i; - pi[axis1] = j; - grid.Grid(pi,axis,cells); - } - } - } - } - sort(cells.begin(),cells.end()); - cells.erase(unique(cells.begin(),cells.end()),cells.end()); - - return false; - } - -/*@}*/ -/** - Basic Function computing the intersection between a trimesh and a plane, provided a pointer - to an space indexing data structure (e.g. a grid, an oct-tree..) -*/ - template < typename TriMeshType, typename EdgeMeshType, class ScalarType, class IndexingType > - bool Intersection( /*TriMeshType & m, */ - Plane3 pl, - EdgeMeshType & em, - double& ave_length, - IndexingType *grid, - typename std::vector< typename IndexingType::Cell* >& cells) -{ - typedef typename TriMeshType::FaceContainer FaceContainer; - typedef IndexingType GridType; - typename EdgeMeshType::VertexIterator vi; - typename TriMeshType::FaceIterator fi; - std::vector v; - v.clear(); - Intersect(*grid,pl,cells); - Segment3 seg; - ave_length = 0.0; - typename std::vector::iterator ic; - typename GridType::Cell fs,ls; - for(ic = cells.begin(); ic != cells.end();++ic) - { - grid->Grid(*ic,fs,ls); - typename GridType::Link * lk = fs; - while(lk != ls){ - typename TriMeshType::FaceType & face = *(lk->Elem()); - if(!face.IsS()) - { - face.SetS(); - v.push_back(&face); - if(vcg::IntersectionPlaneTriangle(pl,face,seg))// intersezione piano triangolo - { - face.SetS(); - // add to em - ave_length+=seg.Length(); - vcg::edg::Allocator::AddEdges(em,1); - vi = vcg::edg::Allocator::AddVertices(em,2); - (*vi).P() = seg.P0(); - em.edges.back().V(0) = &(*vi); - vi++; - (*vi).P() = seg.P1(); - em.edges.back().V(1) = &(*vi); - } - }//endif - lk++; - }//end while - } - ave_length/=em.en; - typename std::vector::iterator v_i; - for(v_i=v.begin(); v_i!=v.end(); ++v_i) (*v_i)->ClearS(); - - return true; -} - -/** \addtogroup complex */ -/*@{*/ -/** - Basic Function computing the intersection between a trimesh and a plane. It returns an EdgeMesh without needing anything else. - Note: This version always returns a segment for each triangle of the mesh which intersects with the plane. In other - words there are 2*n vertices where n is the number of segments fo the mesh. You can run vcg::edge:Unify to unify - the vertices closer that a given value epsilon. Note that, due to subtraction error during triangle plane intersection, - it is not safe to put epsilon to 0. -// TODO si dovrebbe considerare la topologia face-face della trimesh per derivare quella della edge mesh.. -*/ -template < typename TriMeshType, typename EdgeMeshType, class ScalarType > -bool Intersection(TriMeshType & m, - Plane3 pl, - EdgeMeshType & em) -{ - typename EdgeMeshType::VertexIterator vi; - typename TriMeshType::FaceIterator fi; - em.Clear(); - Segment3 seg; - for(fi=m.face.begin();fi!=m.face.end();++fi) - if(!(*fi).IsD()) - { - if(vcg::IntersectionPlaneTriangle(pl,*fi,seg))// intersezione piano triangolo - { - vcg::edg::Allocator::AddEdges(em,1); - vi = vcg::edg::Allocator::AddVertices(em,2); - (*vi).P() = seg.P0(); - em.edges.back().V(0) = &(*vi); - vi++; - (*vi).P() = seg.P1(); - em.edges.back().V(1) = &(*vi); - } - }//end for - - return true; -} - -/** \addtogroup complex */ -/*@{*/ -/** - Compute the intersection between a trimesh and a plane. - given a plane return the set of faces that are contained - into intersected cells. -*/ -template < typename TriMeshType, class ScalarType, class IndexingType > -bool Intersection(Plane3 pl, - IndexingType *grid, - typename std::vector &v) -{ - typedef typename TriMeshType::FaceContainer FaceContainer; - typedef IndexingType GridType; - typename TriMeshType::FaceIterator fi; - v.clear(); - typename std::vector< typename GridType::Cell* > cells; - Intersect(*grid,pl,cells); - typename std::vector::iterator ic; - typename GridType::Cell fs,ls; - - for(ic = cells.begin(); ic != cells.end();++ic) - { - grid->Grid(*ic,fs,ls); - typename GridType::Link * lk = fs; - while(lk != ls){ - typename TriMeshType::FaceType & face = *(lk->Elem()); - v.push_back(&face); - lk++; - }//end while - }//end for - return true; -} - -/** - Computes the intersection between a Ray and a Mesh. Returns a 3D Pointset. -*/ -template < typename TriMeshType, class ScalarType> -bool IntersectionRayMesh( - /* Input Mesh */ TriMeshType * m, - /* Ray */ const Line3 & ray, - /* Intersect Point */ Point3 & hitPoint) -{ - //typedef typename TriMeshType::FaceContainer FaceContainer; - typename TriMeshType::FaceIterator fi; - bool hit=false; - - if(m==0) return false; - - //TriMeshType::FaceIterator fi; - //std::vector::iterator fi; - - ScalarType bar1,bar2,dist; - Point3 p1; - Point3 p2; - Point3 p3; - for(fi = m->face.begin(); fi != m->face.end(); ++fi) - { - p1=vcg::Point3( (*fi).P(0).X() ,(*fi).P(0).Y(),(*fi).P(0).Z() ); - p2=vcg::Point3( (*fi).P(1).X() ,(*fi).P(1).Y(),(*fi).P(1).Z() ); - p3=vcg::Point3( (*fi).P(2).X() ,(*fi).P(2).Y(),(*fi).P(2).Z() ); - if(IntersectionLineTriangle(ray,p1,p2,p3,dist,bar1,bar2)) - { - hitPoint= p1*(1-bar1-bar2) + p2*bar1 + p3*bar2; - hit=true; - } - } - - return hit; -} - -/** - Computes the intersection between a Ray and a Mesh. Returns a 3D Pointset, baricentric's coordinates - and a pointer of intersected face. -*/ -template < typename TriMeshType, class ScalarType> -bool IntersectionRayMesh( - /* Input Mesh */ TriMeshType * m, - /* Ray */ const Line3 & ray, - /* Intersect Point */ Point3 & hitPoint, - /* Baricentric coord 1*/ ScalarType &bar1, - /* Baricentric coord 2*/ ScalarType &bar2, - /* Baricentric coord 3*/ ScalarType &bar3, - /* FacePointer */ typename TriMeshType::FacePointer fp - ) -{ - //typedef typename TriMeshType::FaceContainer FaceContainer; - typename TriMeshType::FaceIterator fi; - bool hit=false; - - if(m==0) return false; - - //TriMeshType::FaceIterator fi; - //std::vector::iterator fi; - - ScalarType dist; - Point3 p1; - Point3 p2; - Point3 p3; - for(fi = m->face.begin(); fi != m->face.end(); ++fi) - { - p1=vcg::Point3( (*fi).P(0).X() ,(*fi).P(0).Y(),(*fi).P(0).Z() ); - p2=vcg::Point3( (*fi).P(1).X() ,(*fi).P(1).Y(),(*fi).P(1).Z() ); - p3=vcg::Point3( (*fi).P(2).X() ,(*fi).P(2).Y(),(*fi).P(2).Z() ); - if(IntersectionLineTriangle(ray,p1,p2,p3,dist,bar1,bar2)) - { - bar3 = (1-bar1-bar2); - hitPoint= p1*bar3 + p2*bar1 + p3*bar2; - fp = &(*fi); - hit=true; - } - } - - return hit; -} - -/** - Compute the intersection between a mesh and a ball. - given a mesh return a new mesh made by a copy of all the faces entirely includeded in the ball plus - new faces created by refining the ones intersected by the ball border. - It works by recursively splitting the triangles that cross the border, as long as their area is greater than - a given value tol. If no value is provided, 1/10^5*2*pi*radius is used - NOTE: the returned mesh is a triangle soup -*/ -template < typename TriMeshType, class ScalarType> -void IntersectionBallMesh( TriMeshType & m, const vcg::Sphere3 &ball, TriMeshType & res, - float tol = 0){ - - typename TriMeshType::VertexIterator v0,v1,v2; - typename TriMeshType::FaceIterator fi; - std::vector closests; - vcg::Point3 witness; - std::pair info; - - if(tol == 0) tol = M_PI * ball.Radius() * ball.Radius() / 100000; - - for(fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD() && IntersectionSphereTriangle(ball ,(*fi), witness , &info)) - closests.push_back(&(*fi)); - - res.Clear(); - SubSet(res,closests); - int i =0; - while(i(ball ,res.face[i], witness , &info) && !allIn){ - if(vcg::DoubleArea(res.face[i]) > tol) - { - // split the face res.face[i] in four, add the four new faces to the mesh and delete the face res.face[i] - v0 = vcg::tri::Allocator::AddVertices(res,3); - fi = vcg::tri::Allocator::AddFaces(res,4); - - v1 = v0; ++v1; - v2 = v1; ++v2; - (*v0).P() = (res.face[i].P(0) + res.face[i].P(1))*0.5; - (*v1).P() = (res.face[i].P(1) + res.face[i].P(2))*0.5; - (*v2).P() = (res.face[i].P(2) + res.face[i].P(0))*0.5; - - (*fi).V(0) = res.face[i].V(0); - (*fi).V(1) = &(*v0); - (*fi).V(2) = &(*v2); - ++fi; - - (*fi).V(0) = res.face[i].V(1); - (*fi).V(1) = &(*v1); - (*fi).V(2) = &(*v0); - ++fi; - - (*fi).V(0) = &(*v0); - (*fi).V(1) = &(*v1); - (*fi).V(2) = &(*v2); - ++fi; - - (*fi).V(0) = &(*v2); - (*fi).V(1) = &(*v1); - (*fi).V(2) = res.face[i].V(2) ; - - vcg::tri::Allocator::DeleteFace(res,res.face[i]); - } - }// there was no intersection with the boundary - - if(info.first > 0.0) // closest point - radius. If >0 is outside - vcg::tri::Allocator::DeleteFace(res,res.face[i]); - ++i; - } -} - - -template < typename TriMeshType, class ScalarType, class IndexingType> -void IntersectionBallMesh( IndexingType * grid, TriMeshType & m, const vcg::Sphere3 &ball, TriMeshType & res, - float tol = 0){ - - typename TriMeshType::VertexIterator v0,v1,v2; - typename std::vector::iterator cfi; - typename TriMeshType::FaceIterator fi; - std::vector closestsF,closests; - vcg::Point3 witness; - std::vector > witnesses; - std::vector distances; - std::pair info; - - if(tol == 0) tol = M_PI * ball.Radius() * ball.Radius() / 100000; - - vcg::tri::GetInSphereFace(m,*grid, ball.Center(), ball.Radius(),closestsF,distances,witnesses); - for(cfi =closestsF.begin(); cfi != closestsF.end(); ++cfi) - if(!(**cfi).IsD() && IntersectionSphereTriangle(ball ,(**cfi), witness , &info)) - closests.push_back(&(**cfi)); - - res.Clear(); - SubSet(res,closests); - int i =0; - while(i(ball ,res.face[i], witness , &info) && !allIn){ - if(vcg::DoubleArea(res.face[i]) > tol) - { - // split the face res.face[i] in four, add the four new faces to the mesh and delete the face res.face[i] - v0 = vcg::tri::Allocator::AddVertices(res,3); - fi = vcg::tri::Allocator::AddFaces(res,4); - - v1 = v0; ++v1; - v2 = v1; ++v2; - (*v0).P() = (res.face[i].P(0) + res.face[i].P(1))*0.5; - (*v1).P() = (res.face[i].P(1) + res.face[i].P(2))*0.5; - (*v2).P() = (res.face[i].P(2) + res.face[i].P(0))*0.5; - - (*fi).V(0) = res.face[i].V(0); - (*fi).V(1) = &(*v0); - (*fi).V(2) = &(*v2); - ++fi; - - (*fi).V(0) = res.face[i].V(1); - (*fi).V(1) = &(*v1); - (*fi).V(2) = &(*v0); - ++fi; - - (*fi).V(0) = &(*v0); - (*fi).V(1) = &(*v1); - (*fi).V(2) = &(*v2); - ++fi; - - (*fi).V(0) = &(*v2); - (*fi).V(1) = &(*v1); - (*fi).V(2) = res.face[i].V(2) ; - - vcg::tri::Allocator::DeleteFace(res,res.face[i]); - } - }// there was no intersection with the boundary - - if(info.first > 0.0) // closest point - radius. If >0 is outside - vcg::tri::Allocator::DeleteFace(res,res.face[i]); - ++i; - } -} - -/*@}*/ -} // end namespace vcg -#endif diff --git a/vcg/complex/trimesh/local_optimization.h b/vcg/complex/trimesh/local_optimization.h deleted file mode 100644 index a567b476..00000000 --- a/vcg/complex/trimesh/local_optimization.h +++ /dev/null @@ -1,398 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ -/**************************************************************************** - $Log: not supported by cvs2svn $ - Revision 1.20 2007/01/19 09:13:09 cignoni - Added Finalize() method to the interface - - Revision 1.19 2007/01/11 11:48:33 ganovelli - currMetric inizialied to heap.front() (it was heap.back()- wrong) - - Revision 1.18 2006/12/11 14:09:44 ganovelli - added missing initialization of currMetric - - Revision 1.17 2006/06/09 07:28:43 m_di_benedetto - Corrected ClearHeap(): iterator "hi" not decrementable if it was the first of the container. - - Revision 1.16 2005/11/10 15:38:46 cignoni - Added casts to remove warnings - - Revision 1.15 2005/10/02 23:23:52 cignoni - Changed the sense of the < operator for heap: it is reversed according to the stl where highest score elements must float in the heap - Completed TimeBudget Termination condition. - Parametrized the ClearHeap procedure now there is a HeapSimplexRatio param. Removed dirty printf. - - Revision 1.14 2005/04/14 11:34:33 ponchio - *** empty log message *** - - Revision 1.13 2005/01/19 10:33:50 cignoni - Improved ClearHeap management - - Revision 1.12 2004/12/10 01:02:48 cignoni - added an inline and removed loggng - - Revision 1.11 2004/12/03 21:14:39 ponchio - Fixed memory leak... - - Revision 1.10 2004/11/23 10:37:17 cignoni - Added a member with a cached copy of the floating Priority() value inside the HeapElem to optimize operator< in heap updating operator - - Revision 1.9 2004/11/05 10:03:47 fiorin - Added ModifierType::TriEdgeFlipOp - - Revision 1.8 2004/10/25 07:02:56 ganovelli - some inline function, logs on file (precompiler directive) - - Revision 1.7 2004/09/29 17:08:39 ganovelli - changed > to < in heapelem comparison - - Revision 1.6 2004/09/28 09:57:08 cignoni - Better Doxygen docs - - Revision 1.5 2004/09/15 10:40:20 ponchio - typedef LocalOptimization HeapType -> public: - - Revision 1.4 2004/09/08 15:10:59 ganovelli - *** empty log message *** - - Revision 1.3 2004/07/27 09:46:15 cignoni - First working version of the LocalOptimization/Simplification Framework - - Revision 1.1 2004/07/15 12:04:14 ganovelli - minor changes - - Revision 1.2 2004/07/09 10:22:56 ganovelli - working draft - - Revision 1.1 2004/07/08 08:25:15 ganovelli - first draft - -****************************************************************************/ - -#ifndef __VCGLIB_LOCALOPTIMIZATION -#define __VCGLIB_LOCALOPTIMIZATION -#include -#include -#include -#include -#include - -namespace vcg{ - -template -class LocalOptimization; - -enum ModifierType{ TetraEdgeCollapseOp, TriEdgeSwapOp, TriVertexSplitOp, - TriEdgeCollapseOp,TetraEdgeSpliOpt,TetraEdgeSwapOp, TriEdgeFlipOp, - QuadDiagCollapseOp, QuadEdgeCollapseOp}; -/** \addtogroup tetramesh */ -/*@{*/ -/// This abstract class define which functions a local modification to be used in the LocalOptimization. -template -class LocalModification -{ - public: - typedef typename LocalOptimization::HeapType HeapType; - typedef typename MeshType::ScalarType ScalarType; - - - inline LocalModification(){}; - virtual ~LocalModification(){}; - - /// return the type of operation - virtual ModifierType IsOfType() = 0 ; - - /// return true if the data have not changed since it was created - virtual bool IsUpToDate() = 0 ; - - /// return true if no constraint disallow this operation to be performed (ex: change of topology in edge collapses) - virtual bool IsFeasible() = 0; - - /// Compute the priority to be used in the heap - virtual ScalarType ComputePriority()=0; - - /// Return the priority to be used in the heap (implement static priority) - virtual ScalarType Priority() const =0; - - /// Perform the operation and return the variation in the number of simplicies (>0 is refinement, <0 is simplification) - virtual void Execute(MeshType &m)=0; - - /// perform initialization - static void Init(MeshType &m, HeapType&); - - /// An approximation of the size of the heap with respect of the number of simplex - /// of the mesh. When this number is exceeded a clear heap purging is performed. - /// so it is should be reasonably larger than the minimum expected size to avoid too frequent clear heap - /// For example for symmetric edge collapse a 5 is a good guess. - /// while for non symmetric edge collapse a larger number like 9 is a better choice - static float HeapSimplexRatio() {return 6.0f;} ; - - virtual const char *Info(MeshType &) {return 0;} - /// Update the heap as a consequence of this operation - virtual void UpdateHeap(HeapType&)=0; -}; //end class local modification - - -/// LocalOptimization: -/// This class implements the algorihms running on 0-1-2-3-simplicial complex that are based on local modification -/// The local modification can be and edge_collpase, or an edge_swap, a vertex plit...as far as they implement -/// the interface defined in LocalModification. -/// Implementation note: in order to keep the local modification itself indepented by its use in this class, they are not -/// really derived by LocalModification. Instead, a wrapper is done to this purpose (see vcg/complex/tetramesh/decimation/collapse.h) - -template -class LocalOptimization -{ -public: - LocalOptimization(MeshType &mm): m(mm){ ClearTermination();e=0.0;HeapSimplexRatio=5;} - - struct HeapElem; - // scalar type - typedef typename MeshType::ScalarType ScalarType; - // type of the heap - typedef typename std::vector HeapType; - // modification type - typedef LocalModification LocModType; - // modification Pointer type - typedef LocalModification * LocModPtrType; - - - - /// termination conditions - enum LOTermination { - LOnSimplices = 0x01, // test number of simplicies - LOnVertices = 0x02, // test number of verticies - LOnOps = 0x04, // test number of operations - LOMetric = 0x08, // test Metric (error, quality...instance dependent) - LOTime = 0x10 // test how much time is passed since the start - } ; - - int tf; - - int nPerfmormedOps, - nTargetOps, - nTargetSimplices, - nTargetVertices; - - float timeBudget; - int start; - ScalarType currMetric; - ScalarType targetMetric; - - // The ratio between Heap size and the number of simplices in the current mesh - // When this value is exceeded a ClearHeap Start; - - float HeapSimplexRatio; - - void SetTerminationFlag (int v){tf |= v;} - void ClearTerminationFlag (int v){tf &= ~v;} - bool IsTerminationFlag (int v){return ((tf & v)!=0);} - - void SetTargetSimplices (int ts ){nTargetSimplices = ts; SetTerminationFlag(LOnSimplices); } - void SetTargetVertices (int tv ){nTargetVertices = tv; SetTerminationFlag(LOnVertices); } - void SetTargetOperations(int to ){nTargetOps = to; SetTerminationFlag(LOnOps); } - - void SetTargetMetric (ScalarType tm ){targetMetric = tm; SetTerminationFlag(LOMetric); } - void SetTimeBudget (float tb ){timeBudget = tb; SetTerminationFlag(LOTime); } - - void ClearTermination() - { - tf=0; - nTargetSimplices=0; - nTargetOps=0; - targetMetric=0; - timeBudget=0; - nTargetVertices=0; - } - /// the mesh to optimize - MeshType & m; - - - - ///the heap of operations - HeapType h; - - ///the element of the heap - // it is just a wrapper of the pointer to the localMod. - // std heap does not work for - // pointers and we want pointers to have heterogenous heaps. - - struct HeapElem - { - inline HeapElem(){locModPtr = NULL;} - ~HeapElem(){} - - ///pointer to instance of local modifier - LocModPtrType locModPtr; - float pri; - - - inline HeapElem( LocModPtrType _locModPtr) - { - locModPtr = _locModPtr; - pri=float(locModPtr->Priority()); - }; - - /// STL heap has the largest element as the first one. - /// usually we mean priority as an error so we should invert the comparison - inline bool operator <(const HeapElem & h) const - { - return (pri > h.pri); - //return (locModPtr->Priority() < h.locModPtr->Priority()); - } - - bool IsUpToDate() - { - return locModPtr->IsUpToDate(); - } - }; - - - - /// Default distructor - ~LocalOptimization(){ - typename HeapType::iterator i; - for(i = h.begin(); i != h.end(); i++) - delete (*i).locModPtr; - }; - - double e; - - /// main cycle of optimization - bool DoOptimization() - { - start=clock(); - nPerfmormedOps =0; - while( !GoalReached() && !h.empty()) - { - if(h.size()> m.SimplexNumber()*HeapSimplexRatio ) ClearHeap(); - std::pop_heap(h.begin(),h.end()); - LocModPtrType locMod = h.back().locModPtr; - currMetric=h.back().pri; - h.pop_back(); - - if( locMod->IsUpToDate() ) - { - //printf("popped out: %s\n",locMod->Info(m)); - // check if it is feasible - if (locMod->IsFeasible()) - { - nPerfmormedOps++; - locMod->Execute(m); - locMod->UpdateHeap(h); - } - } - //else printf("popped out unfeasible\n"); - delete locMod; - } - return !(h.empty()); - } - -// It removes from the heap all the operations that are no more 'uptodate' -// (e.g. collapses that have some recently modified vertices) -// This function is called from time to time by the doOptimization (e.g. when the heap is larger than fn*3) -void ClearHeap() -{ - typename HeapType::iterator hi; - //int sz=h.size(); - for(hi=h.begin();hi!=h.end();) - { - if(!(*hi).locModPtr->IsUpToDate()) - { - delete (*hi).locModPtr; - *hi=h.back(); - if(&*hi==&h.back()) - { - hi=h.end(); - h.pop_back(); - break; - } - h.pop_back(); - continue; - } - ++hi; - } - //qDebug("\nReduced heap from %7i to %7i (fn %7i) ",sz,h.size(),m.fn); - make_heap(h.begin(),h.end()); -} - - ///initialize for all vertex the temporary mark must call only at the start of decimation - ///by default it takes the first element in the heap and calls Init (static funcion) of that type - ///of local modification. - template void Init() - { - vcg::tri::InitVertexIMark(m); - - // The expected size of heap depends on the type of the local modification we are using.. - HeapSimplexRatio = LocalModificationType::HeapSimplexRatio(); - - LocalModificationType::Init(m,h); - std::make_heap(h.begin(),h.end()); - if(!h.empty()) currMetric=h.front().pri; - } - - - template void Finalize() - { - LocalModificationType::Finalize(m,h); - } - - - /// say if the process is to end or not: the process ends when any of the termination conditions is verified - /// override this function to implemetn other tests - bool GoalReached(){ - assert ( ( ( tf & LOnSimplices )==0) || ( nTargetSimplices!= -1)); - assert ( ( ( tf & LOnVertices )==0) || ( nTargetVertices != -1)); - assert ( ( ( tf & LOnOps )==0) || ( nTargetOps != -1)); - assert ( ( ( tf & LOMetric )==0) || ( targetMetric != -1)); - assert ( ( ( tf & LOTime )==0) || ( timeBudget != -1)); - - if ( IsTerminationFlag(LOnSimplices) && ( m.SimplexNumber()<= nTargetSimplices)) return true; - if ( IsTerminationFlag(LOnVertices) && ( m.VertexNumber() <= nTargetVertices)) return true; - if ( IsTerminationFlag(LOnOps) && (nPerfmormedOps == nTargetOps)) return true; - if ( IsTerminationFlag(LOMetric) && ( currMetric > targetMetric)) return true; - if ( IsTerminationFlag(LOTime) && ( (clock()-start)/(float)CLOCKS_PER_SEC > timeBudget)) return true; - return false; - } - - - -///erase from the heap the operations that are out of date - void ClearHeapOld() - { - typename HeapType::iterator hi; - for(hi=h.begin();hi!=h.end();++hi) - if(!(*hi).locModPtr->IsUpToDate()) - { - *hi=h.back(); - h.pop_back(); - if(hi==h.end()) break; - } - //printf("\nReduced heap from %i to %i",sz,h.size()); - make_heap(h.begin(),h.end()); - } - -};//end class decimation - -}//end namespace -#endif diff --git a/vcg/complex/trimesh/nring.h b/vcg/complex/trimesh/nring.h deleted file mode 100644 index 5d1756f8..00000000 --- a/vcg/complex/trimesh/nring.h +++ /dev/null @@ -1,157 +0,0 @@ -#ifndef RINGWALKER_H -#define RINGWALKER_H - -/**************************************************************************** - * VCGLib o o * - * Visual and Computer Graphics Library o o * - * _ O _ * - * Copyright(C) 2004 \/)\/ * - * Visual Computing Lab /\/| * - * ISTI - Italian National Research Council | * - * \ * - * All rights reserved. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * - * for more details. * - * * - ****************************************************************************/ - -#include -#include -#include -#include - -namespace vcg -{ -namespace tri -{ - - /** \addtogroup trimesh */ - /*@{*/ - /*@{*/ - /** Class Mesh. - This is class for extracting n-ring of vertexes or faces, starting from a vertex of a mesh. - */ -template -class Nring -{ -public: - - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::FaceIterator FaceIterator; - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::CoordType CoordType; - - - std::vector allV; - std::vector allF; - - std::vector lastV; - std::vector lastF; - - MeshType* m; - - Nring(VertexType* v, MeshType* m) : m(m) - { - assert((unsigned)(v - &*m->vert.begin()) < m->vert.size()); - insertAndFlag(v); - - } - - ~Nring() - { - clear(); - } - - void insertAndFlag1Ring(VertexType* v) - { - insertAndFlag(v); - - typename face::Pos p(v->VFp(),v); - assert(p.V() == v); - - int count = 0; - face::Pos ori = p; - do - { - insertAndFlag(p.F()); - p.FlipF(); - p.FlipE(); - assert(count++ < 100); - } while (ori != p); - - } - - void insertAndFlag(FaceType* f) - { - if (!f->IsV()) - { - allF.push_back(f); - lastF.push_back(f); - f->SetV(); - insertAndFlag(f->V(0)); - insertAndFlag(f->V(1)); - insertAndFlag(f->V(2)); - } - } - - void insertAndFlag(VertexType* v) - { - if (!v->IsV()) - { - allV.push_back(v); - lastV.push_back(v); - v->SetV(); - } - } - - - static void clearFlags(MeshType* m) - { - tri::UpdateFlags::VertexClearV(*m); - tri::UpdateFlags::FaceClearV(*m); - } - - void clear() - { - for(unsigned i=0; i< allV.size(); ++i) - allV[i]->ClearV(); - for(unsigned i=0; i< allF.size(); ++i) - allF[i]->ClearV(); - - allV.clear(); - allF.clear(); - } - - void expand() - { - std::vector lastVtemp = lastV; - - lastV.clear(); - lastF.clear(); - - for(typename std::vector::iterator it = lastVtemp.begin(); it != lastVtemp.end(); ++it) - { - insertAndFlag1Ring(*it); - } - } - - void expand(int k) - { - for(int i=0;i -#include -#include -#include -#include - -#include - -using namespace std; -using namespace vcg; - -/** \brief This class provides a strategy to estimate the overlap percentage of two range maps/point clouds. - * - * This class can be used, for exemple, into an automatic alignment process to check the quality of the - * transformation found; the idea is that bad alignments should have a small overlap. Two points are - * considered 'overlapping in the righ way' if they are close (i.e distance is less then \c consensusDist) - * and at the same time points' normals match quite well (i.e the angle between them is less then - * \c consensusNormalsAngle). The test to compute the overlap is perfomed on a given number of points - * (2500 is the default) sampled in a normal equalized way (default) or uniformly. - * \author Francesco Tonarelli - */ -template class OverlapEstimation -{ - public: - - typedef MESH_TYPE MeshType; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename vector::iterator VertexPointerIterator; - typedef GridStaticPtr MeshGrid; - typedef tri::VertTmark MarkerVertex; - - private: - /** Private simple class needed to perform sampling of pointers to vertexes. */ - class VertexPointerSampler - { - public: - - MeshType* m; //this is needed for advanced sampling (i.e poisson sampling) - - VertexPointerSampler(){ m = new MeshType(); m->Tr.SetIdentity(); m->sfn=0; } - ~VertexPointerSampler(){ if(m) delete m; } - vector sampleVec; - - void AddVert(VertexType &p){ sampleVec.push_back(&p); } //this function is the only we really need - void AddFace(const FaceType &f, const CoordType &p){} - void AddTextureSample(const FaceType &, const CoordType &, const Point2i &){} - }; - - public: - /** \brief Public class to hold parameters. Used to avoid endless list of parameters inside functions. - * \author Francesco Tonarelli - */ - class Parameters - { - public: - int samples; ///< Number of samples to check to compute the overlap. Higher values get more accurancy but requires more time. - int bestScore; ///< Score to overcome to paint \c mMov . If overlap estimation is called many times inside a loop, you can set this value in each iteration to paint \c mMov and see only the best overlap achived. - float consensusDist; ///< Consensus distance. Lower values should gat more accurancy; high values can lead to performance hit. - float consensusNormalsAngle; ///< Holds the the consensus angle for normals, in gradients. Lower values decrease accurancy, particulary for range maps with many peaks and high frequencies. - float threshold; ///< Consensus percentage requested to win consensus. Used to paint \c mMov. If the overlap overcames the \c threshold (and \c bestScore), \c mMov is painted. - bool normalEqualization; ///< Allows to use normal equalization sampling in consensus. If set to \c false uniform sampling is used instead. Uniform sampling is faster but less accurate. - bool paint; ///< Allows painting of \c mMov according to consensus. See Paint() for details. - void (*log)(int level, const char * f, ... ); ///< Pointer to a log function. - - /** Constructor with default values. */ - Parameters() - { - samples = 2500; - bestScore = 0; - consensusDist = 2.0f; - consensusNormalsAngle = 0.965f; //15 degrees. - threshold = 0.0f; - normalEqualization = true; - paint = false; - log = NULL; - } - }; - - private: - MeshType* mFix; /** Pointer to mesh \c mFix. */ - MeshType* mMov; /** Pointer to mesh \c mMov. */ - vector >* normBuckets; //structure to hold normals bucketing. Needed for normal equalized sampling during consensus - MeshGrid* gridFix; //variable to manage uniform grid - MarkerVertex markerFunctorFix; //variable to manage uniform grid - - public: - /** Default constructor. */ - OverlapEstimation() : normBuckets(NULL), gridFix(NULL){} - /** Default destructor. Deallocates structures. */ - ~OverlapEstimation(){ - if(normBuckets) delete normBuckets; - if(gridFix) delete gridFix; - } - /** Set the fix mesh \c mFix. */ - void SetFix(MeshType& m){ mFix = &m; } - /** Set the move mesh \c mMov. */ - void SetMove(MeshType& m){ mMov = &m; } - - /** Paint \c mMov according to the overlap estimation result. Works only if \c Compute() or \c Check() have - * been previously called with \c Parameters.paint=true .
Legend: \arg \e red: points overlaps correctly. - * \arg \e blue: points are too far to overlap. \arg \e yellow: points are close, but normals mismatch. - */ - void Paint() - { - for(VertexIterator vi=mMov->vert.begin(); vi!=mMov->vert.end(); vi++){ - if(!(*vi).IsD()){ - if((*vi).Q()==0.0) (*vi).C() = Color4b::Red; - if((*vi).Q()==1.0) (*vi).C() = Color4b::Yellow; - if((*vi).Q()==2.0) (*vi).C() = Color4b::Blue; - } - } - } - - /** Initializes structures. - * @param param A reference to a \c Parameter class containing all the desidered options to estimate overlap. - * \return \c true if everything goes right. - */ - bool Init(Parameters& param){ - //builds the uniform grid with mFix vertices - gridFix = new MeshGrid(); - SetupGrid(); - - //if requested, group normals of mMov into 30 buckets. Buckets are used for Vertex Normal Equalization - //in consensus. Bucketing is done here once for all to speed up consensus. - if(normBuckets) {normBuckets->clear(); delete normBuckets; } - if(param.normalEqualization){ - normBuckets = BucketVertexNormal(mMov->vert, 30); - assert(normBuckets); - } - return true; - } - - /** Compute the overlap estimation between \c mFix and \c mMov. - * @param param A reference to a \c Parameter class containing all the desidered options to estimate overlap. - * \return The percentage of overlap in the range \c [0..1] . - */ - float Compute(Parameters& param) - { - return Check(param)/float(param.samples); - } - - /** Compute the overlap estimation between \c mFix and \c mMov. - * @param param A reference to a \c Parameter class containing all the desidered options to estimate overlap. - * \return The number of points that overlap correctly. This number is in the range \c [0..param.samples] . - */ - //IMPORTANT: per vertex normals of mMov and mFix MUST BE PROVIDED YET NORMALIZED!!! - int Check(Parameters& param) - { - //pointer to a function to compute distance beetween points - vertex::PointDistanceFunctor PDistFunct; - - //if no buckets are provided get a vector of vertex pointers sampled uniformly - //else, get a vector of vertex pointers sampled in a normal equalized manner; used as query points - vector queryVert; - if(param.normalEqualization){ - assert(normBuckets); - for(unsigned int i=0; ivert.size(); i++) queryVert.push_back(&(mMov->vert[i]));//do a copy of pointers to vertexes - SampleVertNormalEqualized(queryVert, param.samples); - } - else{ - SampleVertUniform(*mMov, queryVert, param.samples); - } - assert(queryVert.size()!=0); - - //init variables for consensus - float consDist = param.consensusDist*(mMov->bbox.Diag()/100.0f); //consensus distance - int cons_succ = int(param.threshold*(param.samples/100.0f)); //score needed to pass consensus - int consensus = 0; //counts vertices in consensus - float dist; //holds the distance of the closest vertex found - VertexType* closestVertex = NULL; //pointer to the closest vertex - Point3 queryNrm; //the query point normal for consensus - CoordType queryPnt; //the query point for consensus - CoordType closestPnt; //the closest point found in consensus - Matrix33 inv33_matMov(mMov->Tr,3); //3x3 matrix needed to transform normals - Matrix33 inv33_matFix(Inverse(mFix->Tr),3); //3x3 matrix needed to transform normals - - //consensus loop - VertexPointerIterator vi; int i; - for(i=0, vi=queryVert.begin(); vi!=queryVert.end(); vi++, i++) - { - dist = -1.0f; - //set query point; vertex coord is transformed properly in fix mesh coordinates space; the same for normals - queryPnt = Inverse(mFix->Tr) * (mMov->Tr * (*vi)->P()); - queryNrm = inv33_matFix * (inv33_matMov * (*vi)->N()); - //if query point is bbox, the look for a vertex in cDist from the query point - if(mFix->bbox.IsIn(queryPnt)) closestVertex = gridFix->GetClosest(PDistFunct,markerFunctorFix,queryPnt,consDist,dist,closestPnt); - else closestVertex=NULL; //out of bbox, we consider the point not in consensus... - - if(closestVertex!=NULL && dist < consDist){ - assert(closestVertex->P()==closestPnt); //coord and vertex pointer returned by getClosest must be the same - - //point is in consensus distance, now we check if normals are near - if(queryNrm.dot(closestVertex->N())>param.consensusNormalsAngle) //15 degrees - { - consensus++; //got consensus - if(param.paint) (*vi)->Q() = 0.0f; //store 0 as quality - } - else{ - if(param.paint) (*vi)->Q() = 1.0f; //store 1 as quality - } - } - else{ - if(param.paint) (*vi)->Q() = 2.0f; //store 2 as quality - } - } - - //Paint the mesh only if required and if consensus is the best ever found. Colors have been stores as numbers into quality attribute - if(param.paint){ - if(consensus>=param.bestScore && consensus>=cons_succ) Paint(); - } - - return consensus; - } - - private: - /** Fill the vector \c vert with \c sampleNum pointers to vertexes sampled uniformly from mesh \c m . - * @param m Source mesh. - * @param vert Destination vector. - * @param sampleNum Requested number of vertexes. - */ - void SampleVertUniform(MESH_TYPE& m, vector& vert, int sampleNum) - { - VertexPointerSampler sampler; - tri::SurfaceSampling::VertexUniform(m, sampler, sampleNum); - for(unsigned int i=0; i >* BucketVertexNormal(typename MESH_TYPE::VertContainer& vert, int bucketDim = 30) - { - static vector NV; - if(NV.size()==0) GenNormal::Uniform(bucketDim,NV); - - vector >* BKT = new vector >(NV.size()); //NV size is greater then bucketDim, so don't change this! - - int ind; - for(int i=0;i::BestMatchingNormal(vert[i].N(),NV); - (*BKT)[ind].push_back(i); - } - - return BKT; - } - /** Samples the \c vert vector in a normal equalized way. - * \return \c SampleNum pointers to vertexes sampled in a normal equalized way. Pointers are stored in - * the \c vert (i.e it is an \c in/out parameter). - */ - bool SampleVertNormalEqualized(vector& vert, int SampleNum) - { - assert(normBuckets); - // vettore di contatori per sapere quanti punti ho gia' preso per ogni bucket - vector BKTpos(normBuckets->size(),0); - - if(SampleNum >= int(vert.size())) SampleNum= int(vert.size()-1); - - int ind; - for(int i=0;isize()); // Scelgo un Bucket - int &CURpos = BKTpos[ind]; - vector &CUR = (*normBuckets)[ind]; - - if(CURposSet(mFix->vert.begin(),mFix->vert.end()); - markerFunctorFix.SetMesh(mFix); - } -}; - -#endif // OVERLAP_ESTIMATION_H diff --git a/vcg/complex/trimesh/point_sampling.h b/vcg/complex/trimesh/point_sampling.h deleted file mode 100644 index 8a7ae328..00000000 --- a/vcg/complex/trimesh/point_sampling.h +++ /dev/null @@ -1,1468 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ -/**************************************************************************** - -The sampling Class has a set of static functions, that you can call to sample the surface of a mesh. -Each function is templated on the mesh and on a Sampler object s. -Each function calls many time the sample object with the sampling point as parameter. - -Sampler Classes and Sampling algorithms are independent. -Sampler classes exploits the sample that are generated with various algorithms. -For example, you can compute Hausdorff distance (that is a sampler) using various -sampling strategies (montecarlo, stratified etc). - -****************************************************************************/ -#ifndef __VCGLIB_POINT_SAMPLING -#define __VCGLIB_POINT_SAMPLING - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace vcg -{ -namespace tri -{ - -/// Trivial Sampler, an example sampler object that show the required interface used by the sampling class. -/// Most of the sampling classes call the AddFace method with the face containing the sample and its barycentric coord. -/// Beside being an example of how to write a sampler it provides a simple way to use the various sampling classes. -// For example if you just want to get a vector with positions over the surface You have just to write -// -// vector myVec; -// TrivialSampler ts(myVec) -// SurfaceSampling >::Montecarlo(M, ts, SampleNum); -// -// - -template -class TrivialSampler -{ - public: - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::FaceType FaceType; - - TrivialSampler() - { - sampleVec = new std::vector(); - vectorOwner=true; - }; - - TrivialSampler(std::vector &Vec) - { - sampleVec = &Vec; - sampleVec->clear(); - vectorOwner=false; - }; - - ~TrivialSampler() - { - if(vectorOwner) delete sampleVec; - } - - private: - std::vector *sampleVec; - bool vectorOwner; - public: - - void AddVert(const VertexType &p) - { - sampleVec->push_back(p.cP()); - } - void AddFace(const FaceType &f, const CoordType &p) - { - sampleVec->push_back(f.P(0)*p[0] + f.P(1)*p[1] +f.P(2)*p[2] ); - } - - void AddTextureSample(const FaceType &, const CoordType &, const Point2i &, float ) - { - // Retrieve the color of the sample from the face f using the barycentric coord p - // and write that color in a texture image at position - // if edgeDist is > 0 then the corrisponding point is affecting face color even if outside the face area (in texture space) - } -}; // end class TrivialSampler - -template -class SurfaceSampling -{ - typedef typename MetroMesh::CoordType CoordType; - typedef typename MetroMesh::ScalarType ScalarType; - typedef typename MetroMesh::VertexType VertexType; - typedef typename MetroMesh::VertexPointer VertexPointer; - typedef typename MetroMesh::VertexIterator VertexIterator; - typedef typename MetroMesh::FacePointer FacePointer; - typedef typename MetroMesh::FaceIterator FaceIterator; - typedef typename MetroMesh::FaceType FaceType; - typedef typename MetroMesh::FaceContainer FaceContainer; - - typedef typename vcg::SpatialHashTable MeshSHT; - typedef typename vcg::SpatialHashTable::CellIterator MeshSHTIterator; - typedef typename vcg::SpatialHashTable MontecarloSHT; - typedef typename vcg::SpatialHashTable::CellIterator MontecarloSHTIterator; - typedef typename vcg::SpatialHashTable SampleSHT; - typedef typename vcg::SpatialHashTable::CellIterator SampleSHTIterator; - -public: - -static math::MarsenneTwisterRNG &SamplingRandomGenerator() -{ - static math::MarsenneTwisterRNG rnd; - return rnd; -} - -// Returns an integer random number in the [0,i-1] interval using the improve Marsenne-Twister method. -static unsigned int RandomInt(unsigned int i) -{ - return (SamplingRandomGenerator().generate(0) % i); -} - -// Returns a random number in the [0,1) real interval using the improved Marsenne-Twister method. -static double RandomDouble01() -{ - return SamplingRandomGenerator().generate01(); -} - -// Returns a random number in the [0,1] real interval using the improved Marsenne-Twister. -static double RandomDouble01closed() -{ - return SamplingRandomGenerator().generate01closed(); -} - -#define FAK_LEN 1024 -static double LnFac(int n) { - // Tabled log factorial function. gives natural logarithm of n! - - // define constants - static const double // coefficients in Stirling approximation - C0 = 0.918938533204672722, // ln(sqrt(2*pi)) - C1 = 1./12., - C3 = -1./360.; - // C5 = 1./1260., // use r^5 term if FAK_LEN < 50 - // C7 = -1./1680.; // use r^7 term if FAK_LEN < 20 - // static variables - static double fac_table[FAK_LEN]; // table of ln(n!): - static bool initialized = false; // remember if fac_table has been initialized - - - if (n < FAK_LEN) { - if (n <= 1) { - if (n < 0) assert(0);//("Parameter negative in LnFac function"); - return 0; - } - if (!initialized) { // first time. Must initialize table - // make table of ln(n!) - double sum = fac_table[0] = 0.; - for (int i=1; i= pois_bound) continue; // reject if outside valid range - k = (int)(x); - lf = k * pois_g - LnFac(k) - pois_f0; - if (lf >= u * (4.0 - u) - 3.0) break; // quick acceptance - if (u * (u - lf) > 1.0) continue; // quick rejection - if (2.0 * log(u) <= lf) break; // final acceptance - } - return k; -} - - -/** - algorithm poisson random number (Knuth): - init: - Let L ← e^−λ, k ← 0 and p ← 1. - do: - k ← k + 1. - Generate uniform random number u in [0,1] and let p ← p × u. - while p > L. - return k − 1. - - */ -static int Poisson(double lambda) -{ - if(lambda>50) return PoissonRatioUniforms(lambda); - double L = exp(-lambda); - int k =0; - double p = 1.0; - do - { - k = k+1; - p = p*RandomDouble01(); - } while (p>L); - - return k -1; -} - - -static void AllVertex(MetroMesh & m, VertexSampler &ps) -{ - VertexIterator vi; - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - { - if(!(*vi).IsD()) - { - ps.AddVert(*vi); - } - } -} - -/// Sample the vertices in a weighted way. Each vertex has a probability of being chosen -/// that is proportional to its quality. -/// It assumes that you are asking a number of vertices smaller than nv; -/// Algorithm: -/// 1) normalize quality so that sum q == 1; -/// 2) shuffle vertices. -/// 3) for each vertices choose it if rand > thr; - -static void VertexWeighted(MetroMesh & m, VertexSampler &ps, int sampleNum) -{ - ScalarType qSum = 0; - VertexIterator vi; - for(vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if(!(*vi).IsD()) - qSum += (*vi).Q(); - - ScalarType samplePerUnit = sampleNum/qSum; - ScalarType floatSampleNum =0; - std::vector vertVec; - FillAndShuffleVertexPointerVector(m,vertVec); - - std::vector vertUsed(m.vn,false); - - int i=0; int cnt=0; - while(cnt < sampleNum) - { - if(vertUsed[i]) - { - floatSampleNum += vertVec[i]->Q() * samplePerUnit; - int vertSampleNum = (int) floatSampleNum; - floatSampleNum -= (float) vertSampleNum; - - // for every sample p_i in T... - if(vertSampleNum > 1) - { - ps.AddVert(*vertVec[i]); - cnt++; - vertUsed[i]=true; - } - } - i = (i+1)%m.vn; - } -} - -/// Sample the vertices in a uniform way. Each vertex has a probability of being chosen -/// that is proportional to the area it represent. -static void VertexAreaUniform(MetroMesh & m, VertexSampler &ps, int sampleNum) -{ - VertexIterator vi; - for(vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if(!(*vi).IsD()) - (*vi).Q() = 0; - - FaceIterator fi; - for(fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - { - ScalarType areaThird = DoubleArea(*fi)/6.0; - (*fi).V(0).Q()+=areaThird; - (*fi).V(1).Q()+=areaThird; - (*fi).V(2).Q()+=areaThird; - } - - VertexWeighted(m,ps,sampleNum); -} - -static void FillAndShuffleFacePointerVector(MetroMesh & m, std::vector &faceVec) -{ - FaceIterator fi; - for(fi=m.face.begin();fi!=m.face.end();++fi) - if(!(*fi).IsD()) faceVec.push_back(&*fi); - - assert((int)faceVec.size()==m.fn); - - unsigned int (*p_myrandom)(unsigned int) = RandomInt; - std::random_shuffle(faceVec.begin(),faceVec.end(), p_myrandom); -} -static void FillAndShuffleVertexPointerVector(MetroMesh & m, std::vector &vertVec) -{ - VertexIterator vi; - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - if(!(*vi).IsD()) vertVec.push_back(&*vi); - - assert((int)vertVec.size()==m.vn); - - unsigned int (*p_myrandom)(unsigned int) = RandomInt; - std::random_shuffle(vertVec.begin(),vertVec.end(), p_myrandom); -} - -/// Sample the vertices in a uniform way. Each vertex has the same probabiltiy of being chosen. -static void VertexUniform(MetroMesh & m, VertexSampler &ps, int sampleNum) -{ - if(sampleNum>=m.vn) { - AllVertex(m,ps); - return; - } - - std::vector vertVec; - FillAndShuffleVertexPointerVector(m,vertVec); - - for(int i =0; i< sampleNum; ++i) - ps.AddVert(*vertVec[i]); -} - - -static void FaceUniform(MetroMesh & m, VertexSampler &ps, int sampleNum) -{ - if(sampleNum>=m.fn) { - AllFace(m,ps); - return; - } - - std::vector faceVec; - FillAndShuffleFacePointerVector(m,faceVec); - - for(int i =0; i< sampleNum; ++i) - ps.AddFace(*faceVec[i],Barycenter(*faceVec[i])); -} - -static void AllFace(MetroMesh & m, VertexSampler &ps) -{ - FaceIterator fi; - for(fi=m.face.begin();fi!=m.face.end();++fi) - if(!(*fi).IsD()) - { - ps.AddFace(*fi,Barycenter(*fi)); - } -} - - -static void AllEdge(MetroMesh & m, VertexSampler &ps) -{ - // Edge sampling. - typedef typename UpdateTopology::PEdge SimpleEdge; - std::vector< SimpleEdge > Edges; - typename std::vector< SimpleEdge >::iterator ei; - UpdateTopology::FillUniqueEdgeVector(m,Edges); - - for(ei=Edges.begin(); ei!=Edges.end(); ++ei) - { - Point3f interp(0,0,0); - interp[ (*ei).z ]=.5; - interp[((*ei).z+1)%3]=.5; - ps.AddFace(*(*ei).f,interp); - } -} - -// Regular Uniform Edge sampling -// Each edge is subdivided in a number of pieces proprtional to its lenght -// Sample are choosen without touching the vertices. - -static void EdgeUniform(MetroMesh & m, VertexSampler &ps,int sampleNum, bool sampleFauxEdge=true) -{ - typedef typename UpdateTopology::PEdge SimpleEdge; - std::vector< SimpleEdge > Edges; - UpdateTopology::FillUniqueEdgeVector(m,Edges,sampleFauxEdge); - // First loop compute total edge lenght; - float edgeSum=0; - typename std::vector< SimpleEdge >::iterator ei; - for(ei=Edges.begin(); ei!=Edges.end(); ++ei) - edgeSum+=Distance((*ei).v[0]->P(),(*ei).v[1]->P()); - - //qDebug("Edges %i edge sum %f",Edges.size(),edgeSum); - float sampleLen = edgeSum/sampleNum; - //qDebug("EdgesSamples %i Sampling Len %f",sampleNum,sampleLen); - float rest=0; - for(ei=Edges.begin(); ei!=Edges.end(); ++ei) - { - float len = Distance((*ei).v[0]->P(),(*ei).v[1]->P()); - float samplePerEdge = floor((len+rest)/sampleLen); - rest = (len+rest) - samplePerEdge * sampleLen; - float step = 1.0/(samplePerEdge+1); - for(int i=0;i 1.0) - { - interp[1] = 1.0 - interp[1]; - interp[2] = 1.0 - interp[2]; - } - - assert(interp[1] + interp[2] <= 1.0); - interp[0]=1.0-(interp[1] + interp[2]); - return interp; -} - -static void StratifiedMontecarlo(MetroMesh & m, VertexSampler &ps,int sampleNum) -{ - ScalarType area = Stat::ComputeMeshArea(m); - ScalarType samplePerAreaUnit = sampleNum/area; - //qDebug("samplePerAreaUnit %f",samplePerAreaUnit); - // Montecarlo sampling. - double floatSampleNum = 0.0; - - FaceIterator fi; - for(fi=m.face.begin(); fi != m.face.end(); fi++) - if(!(*fi).IsD()) - { - // compute # samples in the current face (taking into account of the remainders) - floatSampleNum += 0.5*DoubleArea(*fi) * samplePerAreaUnit; - int faceSampleNum = (int) floatSampleNum; - - // for every sample p_i in T... - for(int i=0; i < faceSampleNum; i++) - ps.AddFace(*fi,RandomBaricentric()); - floatSampleNum -= (double) faceSampleNum; - } -} - -/** - This function compute montecarlo distribution with an approximate number of samples exploiting the poisson distribution approximation of the binomial distribution. - - For a given triangle t of area a_t, in a Mesh of area A, - if we take n_s sample over the mesh, the number of samples that falls in t - follows the poisson distribution of P(lambda ) with lambda = n_s * (a_t/A). - - To approximate the Binomial we use a Poisson distribution with parameter \lambda = np can be used as an approximation to B(n,p) (it works if n is sufficiently large and p is sufficiently small). - - */ - - -static void MontecarloPoisson(MetroMesh & m, VertexSampler &ps,int sampleNum) -{ - ScalarType area = Stat::ComputeMeshArea(m); - ScalarType samplePerAreaUnit = sampleNum/area; - - FaceIterator fi; - for(fi=m.face.begin(); fi != m.face.end(); fi++) - if(!(*fi).IsD()) - { - float areaT=DoubleArea(*fi) * 0.5f; - int faceSampleNum = Poisson(areaT*samplePerAreaUnit); - - // for every sample p_i in T... - for(int i=0; i < faceSampleNum; i++) - ps.AddFace(*fi,RandomBaricentric()); -// SampleNum -= (double) faceSampleNum; - } -} - -/** - This function computes a montecarlo distribution with an EXACT number of samples. - it works by generating a sequence of consecutive segments proportional to the triangle areas - and actually shooting sample over this line - */ - -static void Montecarlo(MetroMesh & m, VertexSampler &ps,int sampleNum) -{ - typedef std::pair IntervalType; - std::vector< IntervalType > intervals (m.fn+1); - FaceIterator fi; - int i=0; - intervals[i]=std::make_pair(0,FacePointer(0)); - // First loop: build a sequence of consecutive segments proportional to the triangle areas. - for(fi=m.face.begin(); fi != m.face.end(); fi++) - if(!(*fi).IsD()) - { - intervals[i+1]=std::make_pair(intervals[i].first+0.5*DoubleArea(*fi), &*fi); - ++i; - } - ScalarType meshArea = intervals.back().first; - for(i=0;i::iterator it = lower_bound(intervals.begin(),intervals.end(),std::make_pair(val,FacePointer(0)) ); - assert(it != intervals.end()); - assert(it != intervals.begin()); - assert( (*(it-1)).first = val); - ps.AddFace( *(*it).second, RandomBaricentric() ); - } -} - -static ScalarType WeightedArea(FaceType f) -{ - ScalarType averageQ = ( f.V(0)->Q() + f.V(1)->Q() + f.V(2)->Q() ) /3.0; - return DoubleArea(f)*averageQ/2.0; -} - -/// Compute a sampling of the surface that is weighted by the quality -/// the area of each face is multiplied by the average of the quality of the vertices. -/// So the a face with a zero quality on all its vertices is never sampled and a face with average quality 2 get twice the samples of a face with the same area but with an average quality of 1; -static void WeightedMontecarlo(MetroMesh & m, VertexSampler &ps, int sampleNum) -{ - assert(tri::HasPerVertexQuality(m)); - - ScalarType weightedArea = 0; - FaceIterator fi; - for(fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - weightedArea += WeightedArea(*fi); - - ScalarType samplePerAreaUnit = sampleNum/weightedArea; - //qDebug("samplePerAreaUnit %f",samplePerAreaUnit); - // Montecarlo sampling. - double floatSampleNum = 0.0; - for(fi=m.face.begin(); fi != m.face.end(); fi++) - if(!(*fi).IsD()) - { - // compute # samples in the current face (taking into account of the remainders) - floatSampleNum += WeightedArea(*fi) * samplePerAreaUnit; - int faceSampleNum = (int) floatSampleNum; - - // for every sample p_i in T... - for(int i=0; i < faceSampleNum; i++) - ps.AddFace(*fi,RandomBaricentric()); - - floatSampleNum -= (double) faceSampleNum; - } -} - - -// Subdivision sampling of a single face. -// return number of added samples - -static int SingleFaceSubdivision(int sampleNum, const CoordType & v0, const CoordType & v1, const CoordType & v2, VertexSampler &ps, FacePointer fp, bool randSample) -{ - // recursive face subdivision. - if(sampleNum == 1) - { - // ground case. - CoordType SamplePoint; - if(randSample) - { - CoordType rb=RandomBaricentric(); - SamplePoint=v0*rb[0]+v1*rb[1]+v2*rb[2]; - } - else SamplePoint=((v0+v1+v2)*(1.0f/3.0f)); - - ps.AddFace(*fp,SamplePoint); - return 1; - } - - int s0 = sampleNum /2; - int s1 = sampleNum-s0; - assert(s0>0); - assert(s1>0); - - ScalarType w0 = ScalarType(s1)/ScalarType(sampleNum); - ScalarType w1 = 1.0-w0; - // compute the longest edge. - ScalarType maxd01 = SquaredDistance(v0,v1); - ScalarType maxd12 = SquaredDistance(v1,v2); - ScalarType maxd20 = SquaredDistance(v2,v0); - int res; - if(maxd01 > maxd12) - if(maxd01 > maxd20) res = 0; - else res = 2; - else - if(maxd12 > maxd20) res = 1; - else res = 2; - - int faceSampleNum=0; - // break the input triangle along the midpoint of the longest edge. - CoordType pp; - switch(res) - { - case 0 : pp = v0*w0 + v1*w1; - faceSampleNum+=SingleFaceSubdivision(s0,v0,pp,v2,ps,fp,randSample); - faceSampleNum+=SingleFaceSubdivision(s1,pp,v1,v2,ps,fp,randSample); - break; - case 1 : pp = v1*w0 + v2*w1; - faceSampleNum+=SingleFaceSubdivision(s0,v0,v1,pp,ps,fp,randSample); - faceSampleNum+=SingleFaceSubdivision(s1,v0,pp,v2,ps,fp,randSample); - break; - case 2 : pp = v0*w0 + v2*w1; - faceSampleNum+=SingleFaceSubdivision(s0,v0,v1,pp,ps,fp,randSample); - faceSampleNum+=SingleFaceSubdivision(s1,pp,v1,v2,ps,fp,randSample); - break; - } - return faceSampleNum; -} - - -/// Compute a sampling of the surface where the points are regularly scattered over the face surface using a recursive longest-edge subdivision rule. -static void FaceSubdivision(MetroMesh & m, VertexSampler &ps,int sampleNum, bool randSample) -{ - - ScalarType area = Stat::ComputeMeshArea(m); - ScalarType samplePerAreaUnit = sampleNum/area; - //qDebug("samplePerAreaUnit %f",samplePerAreaUnit); - std::vector faceVec; - FillAndShuffleFacePointerVector(m,faceVec); - vcg::tri::UpdateNormals::PerFaceNormalized(m); - vcg::tri::UpdateFlags::FaceProjection(m); - double floatSampleNum = 0.0; - int faceSampleNum; - // Subdivision sampling. - typename std::vector::iterator fi; - for(fi=faceVec.begin(); fi!=faceVec.end(); fi++) - { - const CoordType b0(1.0, 0.0, 0.0); - const CoordType b1(0.0, 1.0, 0.0); - const CoordType b2(0.0, 0.0, 1.0); - // compute # samples in the current face. - floatSampleNum += 0.5*DoubleArea(**fi) * samplePerAreaUnit; - faceSampleNum = (int) floatSampleNum; - if(faceSampleNum>0) - faceSampleNum = SingleFaceSubdivision(faceSampleNum,b0,b1,b2,ps,*fi,randSample); - floatSampleNum -= (double) faceSampleNum; - } -} -//--------- -// Subdivision sampling of a single face. -// return number of added samples - -static int SingleFaceSubdivisionOld(int sampleNum, const CoordType & v0, const CoordType & v1, const CoordType & v2, VertexSampler &ps, FacePointer fp, bool randSample) -{ - // recursive face subdivision. - if(sampleNum == 1) - { - // ground case. - CoordType SamplePoint; - if(randSample) - { - CoordType rb=RandomBaricentric(); - SamplePoint=v0*rb[0]+v1*rb[1]+v2*rb[2]; - } - else SamplePoint=((v0+v1+v2)*(1.0f/3.0f)); - - CoordType SampleBary; -// int axis; -// if(fp->Flags() & FaceType::NORMX ) axis = 0; -// else if(fp->Flags() & FaceType::NORMY ) axis = 1; -// else { -// assert(fp->Flags() & FaceType::NORMZ) ; -// axis =2; -// } -// InterpolationParameters(*fp,axis,SamplePoint,SampleBary); - InterpolationParameters(*fp,SamplePoint,SampleBary[0],SampleBary[1],SampleBary[2]); - ps.AddFace(*fp,SampleBary); - return 1; - } - - int s0 = sampleNum /2; - int s1 = sampleNum-s0; - assert(s0>0); - assert(s1>0); - - ScalarType w0 = ScalarType(s1)/ScalarType(sampleNum); - ScalarType w1 = 1.0-w0; - // compute the longest edge. - ScalarType maxd01 = SquaredDistance(v0,v1); - ScalarType maxd12 = SquaredDistance(v1,v2); - ScalarType maxd20 = SquaredDistance(v2,v0); - int res; - if(maxd01 > maxd12) - if(maxd01 > maxd20) res = 0; - else res = 2; - else - if(maxd12 > maxd20) res = 1; - else res = 2; - - int faceSampleNum=0; - // break the input triangle along the midpoint of the longest edge. - CoordType pp; - switch(res) - { - case 0 : pp = v0*w0 + v1*w1; - faceSampleNum+=SingleFaceSubdivision(s0,v0,pp,v2,ps,fp,randSample); - faceSampleNum+=SingleFaceSubdivision(s1,pp,v1,v2,ps,fp,randSample); - break; - case 1 : pp = v1*w0 + v2*w1; - faceSampleNum+=SingleFaceSubdivision(s0,v0,v1,pp,ps,fp,randSample); - faceSampleNum+=SingleFaceSubdivision(s1,v0,pp,v2,ps,fp,randSample); - break; - case 2 : pp = v0*w0 + v2*w1; - faceSampleNum+=SingleFaceSubdivision(s0,v0,v1,pp,ps,fp,randSample); - faceSampleNum+=SingleFaceSubdivision(s1,pp,v1,v2,ps,fp,randSample); - break; - } - return faceSampleNum; -} - - -/// Compute a sampling of the surface where the points are regularly scattered over the face surface using a recursive longest-edge subdivision rule. -static void FaceSubdivisionOld(MetroMesh & m, VertexSampler &ps,int sampleNum, bool randSample) -{ - - ScalarType area = Stat::ComputeMeshArea(m); - ScalarType samplePerAreaUnit = sampleNum/area; - //qDebug("samplePerAreaUnit %f",samplePerAreaUnit); - std::vector faceVec; - FillAndShuffleFacePointerVector(m,faceVec); - tri::UpdateNormals::PerFaceNormalized(m); - tri::UpdateFlags::FaceProjection(m); - double floatSampleNum = 0.0; - int faceSampleNum; - // Subdivision sampling. - typename std::vector::iterator fi; - for(fi=faceVec.begin(); fi!=faceVec.end(); fi++) - { - // compute # samples in the current face. - floatSampleNum += 0.5*DoubleArea(**fi) * samplePerAreaUnit; - faceSampleNum = (int) floatSampleNum; - if(faceSampleNum>0) - faceSampleNum = SingleFaceSubdivision(faceSampleNum,(**fi).V(0)->cP(), (**fi).V(1)->cP(), (**fi).V(2)->cP(),ps,*fi,randSample); - floatSampleNum -= (double) faceSampleNum; - } -} - - -//--------- - -// Similar Triangles sampling. -// Skip vertex and edges -// Sample per edges includes vertexes, so here we should expect n_samples_per_edge >=4 - -static int SingleFaceSimilar(FacePointer fp, VertexSampler &ps, int n_samples_per_edge) -{ - int n_samples=0; - int i, j; - float segmentNum=n_samples_per_edge -1 ; - float segmentLen = 1.0/segmentNum; - // face sampling. - for(i=1; i < n_samples_per_edge-1; i++) - for(j=1; j < n_samples_per_edge-1-i; j++) - { - //AddSample( v0 + (V1*(double)i + V2*(double)j) ); - CoordType sampleBary(i*segmentLen,j*segmentLen, 1.0 - (i*segmentLen+j*segmentLen) ) ; - n_samples++; - ps.AddFace(*fp,sampleBary); - } - return n_samples; -} -static int SingleFaceSimilarDual(FacePointer fp, VertexSampler &ps, int n_samples_per_edge, bool randomFlag) -{ - int n_samples=0; - float i, j; - float segmentNum=n_samples_per_edge -1 ; - float segmentLen = 1.0/segmentNum; - // face sampling. - for(i=0; i < n_samples_per_edge-1; i++) - for(j=0; j < n_samples_per_edge-1-i; j++) - { - //AddSample( v0 + (V1*(double)i + V2*(double)j) ); - CoordType V0((i+0)*segmentLen,(j+0)*segmentLen, 1.0 - ((i+0)*segmentLen+(j+0)*segmentLen) ) ; - CoordType V1((i+1)*segmentLen,(j+0)*segmentLen, 1.0 - ((i+1)*segmentLen+(j+0)*segmentLen) ) ; - CoordType V2((i+0)*segmentLen,(j+1)*segmentLen, 1.0 - ((i+0)*segmentLen+(j+1)*segmentLen) ) ; - n_samples++; - if(randomFlag) { - CoordType rb=RandomBaricentric(); - ps.AddFace(*fp, V0*rb[0]+V1*rb[1]+V2*rb[2]); - } else ps.AddFace(*fp,(V0+V1+V2)/3.0); - - if( j < n_samples_per_edge-i-2 ) - { - CoordType V3((i+1)*segmentLen,(j+1)*segmentLen, 1.0 - ((i+1)*segmentLen+(j+1)*segmentLen) ) ; - n_samples++; - if(randomFlag) { - CoordType rb=RandomBaricentric(); - ps.AddFace(*fp, V3*rb[0]+V1*rb[1]+V2*rb[2]); - } else ps.AddFace(*fp,(V3+V1+V2)/3.0); - } - } - return n_samples; -} - -// Similar sampling -// Each triangle is subdivided into similar triangles following a generalization of the classical 1-to-4 splitting rule of triangles. -// According to the level of subdivision you get 1, 4 , 9, 16 , triangles. -// Depending on the kind of the sampling strategies we can have two different approach to choosing the sample points. -// 1) you have already sampled both edges and vertices -// 2) you are not going to take samples on edges and vertices. -// -// In the first case you have to consider only internal vertices of the subdivided triangles (to avoid multiple sampling of edges and vertices). -// Therefore the number of internal points is ((k-3)*(k-2))/2. where k is the number of points on an edge (vertex included) -// E.g. for k=4 you get 3 segments on each edges and the original triangle is subdivided -// into 9 smaller triangles and you get (1*2)/2 == 1 only a single internal point. -// So if you want N samples in a triangle you have to solve k^2 -5k +6 - 2N = 0 -// from which you get: -// -// 5 + sqrt( 1 + 8N ) -// k = ------------------- -// 2 -// -// In the second case if you are not interested to skip the sampling on edges and vertices you have to consider as sample number the number of triangles. -// So if you want N samples in a triangle, the number of points on an edge (vertex included) should be simply: -// k = 1 + sqrt(N) -// examples: -// N = 4 -> k = 3 -// N = 9 -> k = 4 - - - -//template -//void Sampling::SimilarFaceSampling() -static void FaceSimilar(MetroMesh & m, VertexSampler &ps,int sampleNum, bool dualFlag, bool randomFlag) -{ - ScalarType area = Stat::ComputeMeshArea(m); - ScalarType samplePerAreaUnit = sampleNum/area; - - // Similar Triangles sampling. - int n_samples_per_edge; - double n_samples_decimal = 0.0; - FaceIterator fi; - - for(fi=m.face.begin(); fi != m.face.end(); fi++) - { - // compute # samples in the current face. - n_samples_decimal += 0.5*DoubleArea(*fi) * samplePerAreaUnit; - int n_samples = (int) n_samples_decimal; - if(n_samples>0) - { - // face sampling. - if(dualFlag) - { - n_samples_per_edge = (int)((sqrt(1.0+8.0*(double)n_samples) +5.0)/2.0); // original for non dual case - n_samples = SingleFaceSimilar(&*fi,ps, n_samples_per_edge); - } else { - n_samples_per_edge = (int)(sqrt((double)n_samples) +1.0); - n_samples = SingleFaceSimilarDual(&*fi,ps, n_samples_per_edge,randomFlag); - } - } - n_samples_decimal -= (double) n_samples; - } -} - - - // Rasterization fuction - // Take a triangle - // T deve essere una classe funzionale che ha l'operatore () - // con due parametri x,y di tipo S esempio: - // class Foo { public void operator()(int x, int y ) { ??? } }; - -// This function does rasterization with a safety buffer area, thus accounting some points actually outside triangle area -// The safety area samples are generated according to face flag BORDER which should be true for texture space border edges -// Use correctSafePointsBaryCoords = true to map safety texels to closest point barycentric coords (on edge). - static void SingleFaceRaster(typename MetroMesh::FaceType &f, VertexSampler &ps, - const Point2 & v0, - const Point2 & v1, - const Point2 & v2, - bool correctSafePointsBaryCoords=true) - { - typedef typename MetroMesh::ScalarType S; - // Calcolo bounding box - Box2i bbox; - Box2 bboxf; - bboxf.Add(v0); - bboxf.Add(v1); - bboxf.Add(v2); - - bbox.min[0] = floor(bboxf.min[0]); - bbox.min[1] = floor(bboxf.min[1]); - bbox.max[0] = ceil(bboxf.max[0]); - bbox.max[1] = ceil(bboxf.max[1]); - - // Calcolo versori degli spigoli - Point2 d10 = v1 - v0; - Point2 d21 = v2 - v1; - Point2 d02 = v0 - v2; - - // Preparazione prodotti scalari - S b0 = (bbox.min[0]-v0[0])*d10[1] - (bbox.min[1]-v0[1])*d10[0]; - S b1 = (bbox.min[0]-v1[0])*d21[1] - (bbox.min[1]-v1[1])*d21[0]; - S b2 = (bbox.min[0]-v2[0])*d02[1] - (bbox.min[1]-v2[1])*d02[0]; - // Preparazione degli steps - S db0 = d10[1]; - S db1 = d21[1]; - S db2 = d02[1]; - // Preparazione segni - S dn0 = -d10[0]; - S dn1 = -d21[0]; - S dn2 = -d02[0]; - - //Calculating orientation - bool flipped = !(d02 * vcg::Point2(-d10[1], d10[0]) >= 0); - - // Calculating border edges - Segment2 borderEdges[3]; - S edgeLength[3]; - unsigned char edgeMask = 0; - - if (f.IsB(0)) { - borderEdges[0] = Segment2(v0, v1); - edgeLength[0] = borderEdges[0].Length(); - edgeMask |= 1; - } - if (f.IsB(1)) { - borderEdges[1] = Segment2(v1, v2); - edgeLength[1] = borderEdges[1].Length(); - edgeMask |= 2; - } - if (f.IsB(2)) { - borderEdges[2] = Segment2(v2, v0); - edgeLength[2] = borderEdges[2].Length(); - edgeMask |= 4; - } - - // Rasterizzazione - double de = v0[0]*v1[1]-v0[0]*v2[1]-v1[0]*v0[1]+v1[0]*v2[1]-v2[0]*v1[1]+v2[0]*v0[1]; - - for(int x=bbox.min[0]-1;x<=bbox.max[0]+1;++x) - { - bool in = false; - S n[3] = { b0-db0-dn0, b1-db1-dn1, b2-db2-dn2}; - for(int y=bbox.min[1]-1;y<=bbox.max[1]+1;++y) - { - if((n[0]>=0 && n[1]>=0 && n[2]>=0) || (n[0]<=0 && n[1]<=0 && n[2]<=0)) - { - typename MetroMesh::CoordType baryCoord; - baryCoord[0] = double(-y*v1[0]+v2[0]*y+v1[1]*x-v2[0]*v1[1]+v1[0]*v2[1]-x*v2[1])/de; - baryCoord[1] = -double( x*v0[1]-x*v2[1]-v0[0]*y+v0[0]*v2[1]-v2[0]*v0[1]+v2[0]*y)/de; - baryCoord[2] = 1-baryCoord[0]-baryCoord[1]; - - ps.AddTextureSample(f, baryCoord, Point2i(x,y), 0); - in = true; - } else { - // Check whether a pixel outside (on a border edge side) triangle affects color inside it - Point2 px(x, y); - Point2 closePoint; - int closeEdge = -1; - S minDst = FLT_MAX; - - // find the closest point (on some edge) that lies on the 2x2 squared neighborhood of the considered point - for (int i=0; i<3; ++i) - { - if (edgeMask & (1 << i)) - { - Point2 close; - S dst; - if ( ((!flipped) && (n[i]<0)) || - ( flipped && (n[i]>0)) ) - { - dst = ((close = ClosestPoint(borderEdges[i], px)) - px).Norm(); - if(dst < minDst && - close.X() > px.X()-1 && close.X() < px.X()+1 && - close.Y() > px.Y()-1 && close.Y() < px.Y()+1) - { - minDst = dst; - closePoint = close; - closeEdge = i; - } - } - } - } - - if (closeEdge >= 0) - { - typename MetroMesh::CoordType baryCoord; - if (correctSafePointsBaryCoords) - { - // Add x,y sample with closePoint barycentric coords (on edge) - baryCoord[closeEdge] = (closePoint - borderEdges[closeEdge].P(1)).Norm()/edgeLength[closeEdge]; - baryCoord[(closeEdge+1)%3] = 1 - baryCoord[closeEdge]; - baryCoord[(closeEdge+2)%3] = 0; - } else { - // Add x,y sample with his own barycentric coords (off edge) - baryCoord[0] = double(-y*v1[0]+v2[0]*y+v1[1]*x-v2[0]*v1[1]+v1[0]*v2[1]-x*v2[1])/de; - baryCoord[1] = -double( x*v0[1]-x*v2[1]-v0[0]*y+v0[0]*v2[1]-v2[0]*v0[1]+v2[0]*y)/de; - baryCoord[2] = 1-baryCoord[0]-baryCoord[1]; - } - ps.AddTextureSample(f, baryCoord, Point2i(x,y), minDst); - in = true; - } - } - n[0] += dn0; - n[1] += dn1; - n[2] += dn2; - } - b0 += db0; - b1 += db1; - b2 += db2; - } -} - -// Generate a random point in volume defined by a box with uniform distribution -static CoordType RandomBox(vcg::Box3 box) -{ - CoordType p = box.min; - p[0] += box.Dim()[0] * RandomDouble01(); - p[1] += box.Dim()[1] * RandomDouble01(); - p[2] += box.Dim()[2] * RandomDouble01(); - return p; -} - -// generate Poisson-disk sample using a set of pre-generated samples (with the Montecarlo algorithm) -// It always return a point. -static VertexPointer getPrecomputedMontecarloSample(Point3i &cell, MontecarloSHT & samplepool) -{ - MontecarloSHTIterator cellBegin; - MontecarloSHTIterator cellEnd; - samplepool.Grid(cell, cellBegin, cellEnd); - return *cellBegin; -} - -// check the radius constrain -static bool checkPoissonDisk(MetroMesh & vmesh, SampleSHT & sht, const Point3 & p, ScalarType radius) -{ - // get the samples closest to the given one - std::vector closests; - - typedef VertTmark MarkerVert; - static MarkerVert mv; - - Box3f bb(p-Point3f(radius,radius,radius),p+Point3f(radius,radius,radius)); - int nsamples = GridGetInBox(sht, mv, bb, closests); - - ScalarType r2 = radius*radius; - for(int i=0; icP()) < r2) - return false; - - return true; -} - -struct PoissonDiskParam -{ - PoissonDiskParam() - { - adaptiveRadiusFlag = false; - radiusVariance =1; - MAXLEVELS = 5; - invertQuality = false; - preGenFlag = false; - preGenMesh = NULL; - } - bool adaptiveRadiusFlag; - float radiusVariance; - bool invertQuality; - bool preGenFlag; // when generating a poisson distribution, you can initialize the set pof omputed points with ALL the vertices of another mesh. Usefull for building progressive refinements. - MetroMesh *preGenMesh; - int MAXLEVELS; -}; - -static ScalarType ComputePoissonDiskRadius(MetroMesh &origMesh, int sampleNum) -{ - ScalarType meshArea = Stat::ComputeMeshArea(origMesh); - // Manage approximately the PointCloud Case, use the half a area of the bbox. - // TODO: If you had the radius a much better approximation could be done. - if(meshArea ==0) - { - meshArea = (origMesh.bbox.DimX()*origMesh.bbox.DimY() + - origMesh.bbox.DimX()*origMesh.bbox.DimZ() + - origMesh.bbox.DimY()*origMesh.bbox.DimZ()); - } - ScalarType diskRadius = sqrt(meshArea / (0.7 * M_PI * sampleNum)); // 0.7 is a density factor - return diskRadius; -} - -static int ComputePoissonSampleNum(MetroMesh &origMesh, ScalarType diskRadius) -{ - ScalarType meshArea = Stat::ComputeMeshArea(origMesh); - int sampleNum = meshArea / (diskRadius*diskRadius *M_PI *0.7) ; // 0.7 is a density factor - return sampleNum; -} - -static void ComputePoissonSampleRadii(MetroMesh &sampleMesh, ScalarType diskRadius, ScalarType radiusVariance, bool invert) -{ - VertexIterator vi; - std::pair minmax = tri::Stat::ComputePerVertexQualityMinMax( sampleMesh); - float minRad = diskRadius / radiusVariance; - float maxRad = diskRadius * radiusVariance; - float deltaQ = minmax.second-minmax.first; - float deltaRad = maxRad-minRad; - for (vi = sampleMesh.vert.begin(); vi != sampleMesh.vert.end(); vi++) - { - (*vi).Q() = minRad + deltaRad*((invert ? minmax.second - (*vi).Q() : (*vi).Q() - minmax.first )/deltaQ); - } -} - -// Trivial approach that puts all the samples in a UG and removes all the ones that surely do not fit the -static void PoissonDiskPruning(MetroMesh &origMesh, VertexSampler &ps, MetroMesh &montecarloMesh, ScalarType diskRadius, const struct PoissonDiskParam pp=PoissonDiskParam()) -{ - // spatial index of montecarlo samples - used to choose a new sample to insert - MontecarloSHT montecarloSHT; - // initialize spatial hash table for searching - // radius is the radius of empty disk centered over the samples (e.g. twice of the empty space disk) - // This radius implies that when we pick a sample in a cell all that cell will not be touched again. - ScalarType cellsize = 2.0f* diskRadius / sqrt(3.0); - - // inflating - origMesh.bbox.Offset(cellsize); - - int sizeX = std::max(1.0f,origMesh.bbox.DimX() / cellsize); - int sizeY = std::max(1.0f,origMesh.bbox.DimY() / cellsize); - int sizeZ = std::max(1.0f,origMesh.bbox.DimZ() / cellsize); - Point3i gridsize(sizeX, sizeY, sizeZ); -#ifdef QT_VERSION - qDebug("PDS: radius %f Grid:(%i %i %i) ",diskRadius,sizeX,sizeY,sizeZ); - QTime tt; tt.start(); -#endif - - // if we are doing variable density sampling we have to prepare the random samples quality with the correct expected radii. - if(pp.adaptiveRadiusFlag) - ComputePoissonSampleRadii(montecarloMesh, diskRadius, pp.radiusVariance, pp.invertQuality); - - montecarloSHT.InitEmpty(origMesh.bbox, gridsize); - - for (VertexIterator vi = montecarloMesh.vert.begin(); vi != montecarloMesh.vert.end(); vi++) - montecarloSHT.Add(&(*vi)); - - montecarloSHT.UpdateAllocatedCells(); - - - unsigned int (*p_myrandom)(unsigned int) = RandomInt; - std::random_shuffle(montecarloSHT.AllocatedCells.begin(),montecarloSHT.AllocatedCells.end(), p_myrandom); - -#ifdef QT_VERSION - qDebug("PDS: Completed creation of activeCells, %i cells (%i msec)", (int)montecarloSHT.AllocatedCells.size(), tt.restart()); -#endif -int removedCnt=0; - if(pp.preGenFlag) - { - // Initial pass for pruning the Hashed grid with the an eventual pre initialized set of samples - for(VertexIterator vi =pp.preGenMesh->vert.begin(); vi!=pp.preGenMesh->vert.end();++vi) - { - ps.AddVert(*vi); - removedCnt += montecarloSHT.RemoveInSphere(vi->cP(),diskRadius); - } - montecarloSHT.UpdateAllocatedCells(); -#ifdef QT_VERSION - qDebug("Removed %i samples in %i",removedCnt,tt.restart()); -#endif - } - while(!montecarloSHT.AllocatedCells.empty()) - { - removedCnt=0; - for (size_t i = 0; i < montecarloSHT.AllocatedCells.size(); i++) - { - if( montecarloSHT.EmptyCell(montecarloSHT.AllocatedCells[i]) ) continue; - VertexPointer sp = getPrecomputedMontecarloSample(montecarloSHT.AllocatedCells[i], montecarloSHT); - ps.AddVert(*sp); - ScalarType sampleRadius = diskRadius; - if(pp.adaptiveRadiusFlag) sampleRadius = sp->Q(); - removedCnt += montecarloSHT.RemoveInSphere(sp->cP(),sampleRadius); - } - -#ifdef QT_VERSION - qDebug("Removed %i samples in %i",removedCnt,tt.restart()); -#endif - montecarloSHT.UpdateAllocatedCells(); - } -} - -/** Compute a Poisson-disk sampling of the surface. - * The radius of the disk is computed according to the estimated sampling density. - * - * This algorithm is an adaptation of the algorithm of White et al. : - * - * "Poisson Disk Point Set by Hierarchical Dart Throwing" - * K. B. White, D. Cline, P. K. Egbert, - * IEEE Symposium on Interactive Ray Tracing, 2007, - * 10-12 Sept. 2007, pp. 129-132. - */ -static void PoissonDisk(MetroMesh &origMesh, VertexSampler &ps, MetroMesh &montecarloMesh, ScalarType diskRadius, const struct PoissonDiskParam pp=PoissonDiskParam()) -{ - - // spatial index of montecarlo samples - used to choose a new sample to insert - MontecarloSHT montecarloSHTVec[5]; - - - - // initialize spatial hash table for searching - // radius is the radius of empty disk centered over the samples (e.g. twice of the empty space disk) - // This radius implies that when we pick a sample in a cell all that cell will not be touched again. - ScalarType cellsize = 2.0f* diskRadius / sqrt(3.0); - - // inflating - origMesh.bbox.Offset(cellsize); - - int sizeX = std::max(1.0f,origMesh.bbox.DimX() / cellsize); - int sizeY = std::max(1.0f,origMesh.bbox.DimY() / cellsize); - int sizeZ = std::max(1.0f,origMesh.bbox.DimZ() / cellsize); - Point3i gridsize(sizeX, sizeY, sizeZ); -#ifdef QT_VERSION - qDebug("PDS: radius %f Grid:(%i %i %i) ",diskRadius,sizeX,sizeY,sizeZ); - QTime tt; tt.start(); -#endif - - // spatial hash table of the generated samples - used to check the radius constrain - SampleSHT checkSHT; - checkSHT.InitEmpty(origMesh.bbox, gridsize); - - - // sampling algorithm - // ------------------ - // - // - generate millions of samples using montecarlo algorithm - // - extract a cell (C) from the active cell list (with probability proportional to cell's volume) - // - generate a sample inside C by choosing one of the contained pre-generated samples - // - if the sample violates the radius constrain discard it, and add the cell to the cells-to-subdivide list - // - iterate until the active cell list is empty or a pre-defined number of subdivisions is reached - // - - int level = 0; - - // initialize spatial hash to index pre-generated samples - montecarloSHTVec[0].InitEmpty(origMesh.bbox, gridsize); - // create active cell list - for (VertexIterator vi = montecarloMesh.vert.begin(); vi != montecarloMesh.vert.end(); vi++) - montecarloSHTVec[0].Add(&(*vi)); - montecarloSHTVec[0].UpdateAllocatedCells(); - - // if we are doing variable density sampling we have to prepare the random samples quality with the correct expected radii. - if(pp.adaptiveRadiusFlag) - ComputePoissonSampleRadii(montecarloMesh, diskRadius, pp.radiusVariance, pp.invertQuality); - - do - { - MontecarloSHT &montecarloSHT = montecarloSHTVec[level]; - - if(level>0) - {// initialize spatial hash with the remaining points - montecarloSHT.InitEmpty(origMesh.bbox, gridsize); - // create active cell list - for (typename MontecarloSHT::HashIterator hi = montecarloSHTVec[level-1].hash_table.begin(); hi != montecarloSHTVec[level-1].hash_table.end(); hi++) - montecarloSHT.Add((*hi).second); - montecarloSHT.UpdateAllocatedCells(); - } - // shuffle active cells - unsigned int (*p_myrandom)(unsigned int) = RandomInt; - std::random_shuffle(montecarloSHT.AllocatedCells.begin(),montecarloSHT.AllocatedCells.end(), p_myrandom); -#ifdef QT_VERSION - qDebug("PDS: Init of Hashing grid %i cells and %i samples (%i msec)", montecarloSHT.AllocatedCells.size(), montecarloSHT.hash_table.size(), tt.restart()); -#endif - - // generate a sample inside C by choosing one of the contained pre-generated samples - ////////////////////////////////////////////////////////////////////////////////////////// - int removedCnt=montecarloSHT.hash_table.size(); - int addedCnt=checkSHT.hash_table.size(); - for (int i = 0; i < montecarloSHT.AllocatedCells.size(); i++) - { - for(int j=0;j<4;j++) - { - if( montecarloSHT.EmptyCell(montecarloSHT.AllocatedCells[i]) ) continue; - - // generate a sample chosen from the pre-generated one - typename MontecarloSHT::HashIterator hi = montecarloSHT.hash_table.find(montecarloSHT.AllocatedCells[i]); - - if(hi==montecarloSHT.hash_table.end()) {break;} - VertexPointer sp = (*hi).second; - // vr spans between 3.0*r and r / 4.0 according to vertex quality - ScalarType sampleRadius = diskRadius; - if(pp.adaptiveRadiusFlag) sampleRadius = sp->Q(); - if (checkPoissonDisk(*ps.m, checkSHT, sp->cP(), sampleRadius)) - { - ps.AddVert(*sp); - montecarloSHT.RemoveCell(sp); - checkSHT.Add(sp); - break; - } - else - montecarloSHT.RemovePunctual(sp); - } - } - addedCnt = checkSHT.hash_table.size()-addedCnt; - removedCnt = removedCnt-montecarloSHT.hash_table.size(); - - // proceed to the next level of subdivision - // increase grid resolution - gridsize *= 2; - - // -#ifdef QT_VERSION - qDebug("PDS: Pruning %i added %i and removed %i samples (%i msec)",level,addedCnt, removedCnt,tt.restart()); -#endif - level++; - } while(level < 5); -} - -//template -//void Sampling::SimilarFaceSampling() - -// This function also generates samples outside faces if those affects faces in texture space. -// Use correctSafePointsBaryCoords = true to map safety texels to closest point barycentric coords (on edge) -// otherwise obtained samples will map to barycentric coord actually outside face -// -// If you don't need to get those extra points clear faces Border Flags -// vcg::tri::UpdateFlags::FaceClearB(m); -// -// Else make sure to update border flags from texture space FFadj -// vcg::tri::UpdateTopology::FaceFaceFromTexCoord(m); -// vcg::tri::UpdateFlags::FaceBorderFromFF(m); -static void Texture(MetroMesh & m, VertexSampler &ps, int textureWidth, int textureHeight, bool correctSafePointsBaryCoords=true) -{ - FaceIterator fi; - - printf("Similar Triangles face sampling\n"); - for(fi=m.face.begin(); fi != m.face.end(); fi++) - if (!fi->IsD()) - { - Point2f ti[3]; - for(int i=0;i<3;++i) - ti[i]=Point2f((*fi).WT(i).U() * textureWidth - 0.5, (*fi).WT(i).V() * textureHeight - 0.5); - // - 0.5 constants are used to obtain correct texture mapping - - SingleFaceRaster(*fi, ps, ti[0],ti[1],ti[2], correctSafePointsBaryCoords); - } -} - -typedef GridStaticPtr TriMeshGrid; - -class RRParam -{ -public: -float offset; -float minDiag; -tri::FaceTmark markerFunctor; -TriMeshGrid gM; -}; - -static void RegularRecursiveOffset(MetroMesh & m, std::vector &pvec, ScalarType offset, float minDiag) -{ - Box3 bb=m.bbox; - bb.Offset(offset*2.0); - - RRParam rrp; - - rrp.markerFunctor.SetMesh(&m); - - rrp.gM.Set(m.face.begin(),m.face.end(),bb); - - - rrp.offset=offset; - rrp.minDiag=minDiag; - SubdivideAndSample(m, pvec, bb, rrp, bb.Diag()); -} - -static void SubdivideAndSample(MetroMesh & m, std::vector &pvec, const Box3 bb, RRParam &rrp, float curDiag) -{ - Point3f startPt = bb.Center(); - - ScalarType dist; - // Compute mesh point nearest to bb center - FaceType *nearestF=0; - float dist_upper_bound = curDiag+rrp.offset; - Point3f closestPt; - vcg::face::PointDistanceBaseFunctor PDistFunct; - dist=dist_upper_bound; - nearestF = rrp.gM.GetClosest(PDistFunct,rrp.markerFunctor,startPt,dist_upper_bound,dist,closestPt); - curDiag /=2; - if(dist < dist_upper_bound) - { - if(curDiag/3 < rrp.minDiag) //store points only for the last level of recursion (?) - { - if(rrp.offset==0) - pvec.push_back(closestPt); - else - { - if(dist>rrp.offset) // points below the offset threshold cannot be displaced at the right offset distance, we can only make points nearer. - { - Point3f delta = startPt-closestPt; - pvec.push_back(closestPt+delta*(rrp.offset/dist)); - } - } - } - if(curDiag < rrp.minDiag) return; - Point3f hs = (bb.max-bb.min)/2; - for(int i=0;i<2;i++) - for(int j=0;j<2;j++) - for(int k=0;k<2;k++) - SubdivideAndSample(m,pvec, - Box3f(Point3f( bb.min[0]+i*hs[0], bb.min[1]+j*hs[1], bb.min[2]+k*hs[2]), - Point3f(startPt[0]+i*hs[0],startPt[1]+j*hs[1],startPt[2]+k*hs[2])),rrp,curDiag); - - } -} -}; // end class - - -} // end namespace tri -} // end namespace vcg - -#endif - diff --git a/vcg/complex/trimesh/polygon_support.h b/vcg/complex/trimesh/polygon_support.h deleted file mode 100644 index 0ef331c1..00000000 --- a/vcg/complex/trimesh/polygon_support.h +++ /dev/null @@ -1,178 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ - -#ifndef __VCGLIB_POLYGON_SUPPORT -#define __VCGLIB_POLYGON_SUPPORT - -#include -#include -#include -#include - -namespace vcg -{ - namespace tri{ - /// \ingroup trimesh - - /// \headerfile polygon_support.h vcg/complex/trimesh/polygon_support.h - - /// \brief This class is used convert between polygonal meshes and triangular meshes - - /** - This class contains two members that allow to build a triangular mesh from a polygonal mesh - and viceversa. In a trimesh, the generic polygons with n sides are codified represented by tagging the internal edge of the face - with the SetF. - */ - - template - struct PolygonSupport{ - - /** - Import a trianglemesh from a polygon mesh - **/ - static void ImportFromPolyMesh(TriMeshType & tm, PolyMeshType & pm){ - std::vector points; - std::vector faces; - - // the vertices are the same, simply import them - typename PolyMeshType::VertexIterator vi; - typename TriMeshType::FaceIterator tfi,tfib ; - typename TriMeshType ::VertexIterator tvi = Allocator::AddVertices(tm,pm.vert.size()); - int cnt = 0; - for(tvi = tm.vert.begin(),vi = pm.vert.begin(); tvi != tm.vert.end(); ++tvi,++vi,++cnt) - if(!(*vi).IsD()) (*tvi).ImportData(*vi); else vcg::tri::Allocator::DeleteVertex(tm,(*tvi)); - - typename PolyMeshType::FaceIterator fi; - for(fi = pm.face.begin(); fi != pm.face.end(); ++fi) - if(!((*fi).IsD())){ - points.clear(); - for(int i = 0; i < (*fi).VN(); ++i) { - typename PolyMeshType::VertexType * v = (*fi).V(i); - points.push_back(v->P()); - } - faces.clear(); - TessellatePlanarPolygon3(points,faces); - tfib = tfi = Allocator::AddFaces(tm,faces.size()/3); - for(int i = 0; tfi != tm.face.end();++tfi){ - (*tfi).V(0) = &tm.vert[ (*fi).V( faces[i] ) - &(*pm.vert.begin())]; - (*tfi).V(1) = &tm.vert[ (*fi).V( faces[i+1]) - &(*pm.vert.begin())]; - (*tfi).V(2) = &tm.vert[ (*fi).V( faces[i+2]) - &(*pm.vert.begin())]; - // set the F flags - if( (faces[i]+1)%points.size() != faces[i+1]) (*tfi).SetF(0); - if( (faces[i+1]+1)%points.size() != faces[i+2]) (*tfi).SetF(1); - if( (faces[i+2]+1)%points.size() != faces[i]) (*tfi).SetF(2); - i+=3; - } - - } - } - - - /** - Import a polygon mesh from a triangle mesh - **/ - static void ImportFromTriMesh( PolyMeshType & pm, TriMeshType & tm){ - - // the vertices are the same, simply import them - int cnt = 0; - typename TriMeshType ::ConstVertexIterator tvi; - typename PolyMeshType::VertexIterator vi = vcg::tri::Allocator::AddVertices(pm,tm.vert.size()); - for(tvi = tm.vert.begin(); tvi != tm.vert.end(); ++tvi,++vi,++cnt) - if(!(*tvi).IsD())(*vi).ImportData(*tvi); else vcg::tri::Allocator ::DeleteVertex(pm,(*vi)); - - // convert the faces - typename TriMeshType::FaceIterator tfi; - vcg::face::JumpingPos p; - - for( tfi = tm.face.begin(); tfi != tm.face.end(); ++tfi) if(!(*tfi).IsD() && !(*tfi).IsV()) - { - std::vector vs;// vertices of the polygon - std::vector fs;// triangle faces corresponding to the polygon - - - // find a non tagged edge - int se = 0; - for(;se < 3;++se) if (!(*tfi).IsF(se)) break; - - // initialize a pos on the first non tagged edge - typename TriMeshType::VertexPointer v0 = (*tfi).V(se); - p.F() = &(*tfi); - p.E() = se; - p.V() = p.F()->V(p.F()->Next(se)); - p.FlipE(); - - vs.push_back(p.F()->V(se)); - - do{ - while(p.F()->IsF(p.E())) { fs.push_back(p.F()); p.FlipF(); p.FlipE(); p.F()->SetV();} - vs.push_back(p.F()->V(p.E())); - p.FlipV(); - p.FlipE(); - } while( p.V() != v0 ); - - //now vs contains all the vertices of the polygon (still in the trimesh) - typename PolyMeshType::FaceIterator pfi = vcg::tri::Allocator::AddFaces(pm,1); - (*pfi).Alloc(vs.size()); - for( int i = 0 ; i < vs.size(); ++i) - (*pfi).V(i) = ( typename PolyMeshType::VertexType*) & pm.vert[vs[i]-&(*tm.vert.begin())]; - // here handle the other compoenents of the face (how the conponents of the n triangle faces goes in the - // the property of the polygon (e.g. the normal, the color, the quality and so on) - // TODO - - } - } - - static void ExtractPolygon(typename TriMeshType::FacePointer tfi, std::vector &vs){ - vs.clear(); - // find a non tagged edge - int se = -1; - for(int i=0; i<3; i++) if (!( tfi->IsF(i))) { se = i; break;} - - assert(se!=-1); // else, all faux edges! - - // initialize a pos on the first non faux edge - typename TriMeshType::VertexPointer v0 = tfi->V(se); - - vcg::face::JumpingPos p; - - p.F() = tfi; - p.E() = se; - p.V() = p.F()->V(p.F()->Next(se)); - p.FlipE(); - - vs.push_back(p.F()->V(se)); - - int guard = 0; - do{ - while(p.F()->IsF(p.E())) { p.FlipF(); p.FlipE(); p.F()->SetV(); if (guard++>10) break;} - if (guard++>10) break; - vs.push_back(p.F()->V(p.E())); - p.FlipV(); - p.FlipE(); - } while( p.V() != v0 ); - } - -}; // end of struct -}} // end namespace vcg::tri - -#endif // __VCGLIB_TRI_CLIP diff --git a/vcg/complex/trimesh/refine.h b/vcg/complex/trimesh/refine.h deleted file mode 100644 index 49ee79e3..00000000 --- a/vcg/complex/trimesh/refine.h +++ /dev/null @@ -1,924 +0,0 @@ -/***********F***************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ - -#ifndef __VCGLIB_REFINE -#define __VCGLIB_REFINE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace vcg{ - -/* A very short intro about the generic refinement framework, - the main fuction is the - - template - bool RefineE(MESH_TYPE &m, MIDPOINT mid, EDGEPRED ep,bool RefineSelected=false, CallBackPos *cb = 0) - - You have to provide two functor objects to this, one for deciding what edge has to be spltted and one to decide position and new values for the attributes of the new point. - - for example the minimal EDGEPRED is - - template class EdgeLen - { - public: - FLT thr2; - bool operator()(face::Pos ep) const - { - return SquaredDistance(ep.f->V(ep.z)->P(), ep.f->V1(ep.z)->P())>thr2; - } - }; - - With a bit of patience you can customize to make also slicing operation. - -*/ - - -/* The table which encodes how to subdivide a triangle depending - on the splitted edges is organized as such: - - TriNum (the first number): encodes the number of triangles - TV (the following 4 triples): encodes the resulting triangles where - 0, 1, 2 are the original vertices of the triangles and 3, 4, 5 - (mp01, mp12, mp20) are the midpoints of the three edges. - - In the case two edges are splitted the triangle has 2 possible splittings: -we need to choose a diagonal of the resulting trapezoid. -'swap' encodes the two diagonals to test: if diag1 < diag2 we swap the diagonal -like this (140, 504 -> 150, 514) (the second vertex of each triangles is replaced - by the first vertex of the other one). - 2 - / \ - 5---4 - / \ - 0-------1 - -*/ - -class Split { -public: - int TriNum; // number of triangles - int TV[4][3]; // The triangles coded as the following convention - // 0..2 vertici originali del triangolo - // 3..5 mp01, mp12, mp20 midpoints of the three edges - int swap[2][2]; // the two diagonals to test for swapping - int TE[4][3]; // the edge-edge correspondence between refined triangles and the old one - // (3) means the edge of the new triangle is internal; -}; - -const Split SplitTab[8]={ -/* m20 m12 m01 */ -/* 0 0 0 */ {1, {{0,1,2},{0,0,0},{0,0,0},{0,0,0}}, {{0,0},{0,0}}, {{0,1,2},{0,0,0},{0,0,0},{0,0,0}} }, -/* 0 0 1 */ {2, {{0,3,2},{3,1,2},{0,0,0},{0,0,0}}, {{0,0},{0,0}}, {{0,3,2},{0,1,3},{0,0,0},{0,0,0}} }, -/* 0 1 0 */ {2, {{0,1,4},{0,4,2},{0,0,0},{0,0,0}}, {{0,0},{0,0}}, {{0,1,3},{3,1,2},{0,0,0},{0,0,0}} }, -/* 0 1 1 */ {3, {{3,1,4},{0,3,2},{4,2,3},{0,0,0}}, {{0,4},{3,2}}, {{0,1,3},{0,3,2},{1,3,3},{0,0,0}} }, -/* 1 0 0 */ {2, {{0,1,5},{5,1,2},{0,0,0},{0,0,0}}, {{0,0},{0,0}}, {{0,3,2},{3,1,2},{0,0,0},{0,0,0}} }, -/* 1 0 1 */ {3, {{0,3,5},{3,1,5},{2,5,1},{0,0,0}}, {{3,2},{5,1}}, {{0,3,2},{0,3,3},{2,3,1},{0,0,0}} }, -/* 1 1 0 */ {3, {{2,5,4},{0,1,5},{4,5,1},{0,0,0}}, {{0,4},{5,1}}, {{2,3,1},{0,3,2},{3,3,1},{0,0,0}} }, -/* 1 1 1 */ //{4, {{0,3,5},{3,1,4},{5,4,2},{3,4,5}}, {{0,0},{0,0}}, {{0,3,2},{0,1,3},{3,1,2},{3,3,3}} }, -/* 1 1 1 */ {4, {{3,4,5},{0,3,5},{3,1,4},{5,4,2}}, {{0,0},{0,0}}, {{3,3,3},{0,3,2},{0,1,3},{3,1,2}} }, -}; - -// Basic subdivision class -// This class must provide methods for finding the position of the newly created vertices -// In this implemenation we simply put the new vertex in the MidPoint position. -// Color and TexCoords are interpolated accordingly. -template -struct MidPoint : public std::unary_function , typename MESH_TYPE::CoordType > -{ - MidPoint(MESH_TYPE *_mp) { mp=_mp; } - - MESH_TYPE *mp; - - void operator()(typename MESH_TYPE::VertexType &nv, face::Pos ep){ - assert(mp); - nv.P()= (ep.f->V(ep.z)->P()+ep.f->V1(ep.z)->P())/2.0; - - if( MESH_TYPE::HasPerVertexNormal()) - nv.N()= (ep.f->V(ep.z)->N()+ep.f->V1(ep.z)->N()).normalized(); - - if( MESH_TYPE::HasPerVertexColor()) - nv.C().lerp(ep.f->V(ep.z)->C(),ep.f->V1(ep.z)->C(),.5f); - - if( MESH_TYPE::HasPerVertexQuality()) - nv.Q() = ((ep.f->V(ep.z)->Q()+ep.f->V1(ep.z)->Q())) / 2.0; - - if( tri::HasPerVertexTexCoord(*mp)) - nv.T().P() = ((ep.f->V(ep.z)->T().P()+ep.f->V1(ep.z)->T().P())) / 2.0; - } - - Color4 WedgeInterp(Color4 &c0, Color4 &c1) - { - Color4 cc; - return cc.lerp(c0,c1,0.5f); - } - - template - TexCoord2 WedgeInterp(TexCoord2 &t0, TexCoord2 &t1) - { - TexCoord2 tmp; - assert(t0.n()== t1.n()); - tmp.n()=t0.n(); - tmp.t()=(t0.t()+t1.t())/2.0; - return tmp; - } -}; - - - -template -struct MidPointArc : public std::unary_function , typename MESH_TYPE::CoordType> -{ - void operator()(typename MESH_TYPE::VertexType &nv, face::Pos ep) - { - const typename MESH_TYPE::ScalarType EPS =1e-10; - typename MESH_TYPE::CoordType vp = (ep.f->V(ep.z)->P()+ep.f->V1(ep.z)->P())/2.0; - typename MESH_TYPE::CoordType n = (ep.f->V(ep.z)->N()+ep.f->V1(ep.z)->N())/2.0; - typename MESH_TYPE::ScalarType w =n.Norm(); - if(wV(ep.z)->P()+ep.f->V1(ep.z)->P())/2.0; return;} - n/=w; - typename MESH_TYPE::CoordType d0 = ep.f->V(ep.z)->P() - vp; - typename MESH_TYPE::CoordType d1 = ep.f->V1(ep.z)->P()- vp; - typename MESH_TYPE::ScalarType d=Distance(ep.f->V(ep.z)->P(),ep.f->V1(ep.z)->P())/2.0; - - typename MESH_TYPE::CoordType nn = ep.f->V1(ep.z)->N() ^ ep.f->V(ep.z)->N(); - typename MESH_TYPE::CoordType np = n ^ d0; //vector perpendicular to the edge plane, normal is interpolated - np.Normalize(); - double sign=1; - if(np*nn<0) sign=-1; // se le normali non divergono sposta il punto nella direzione opposta - - typename MESH_TYPE::CoordType n0=ep.f->V(ep.z)->N() -np*(ep.f->V(ep.z)->N()*np); - n0.Normalize(); - typename MESH_TYPE::CoordType n1=ep.f->V1(ep.z)->N()-np*(ep.f->V1(ep.z)->N()*np); - assert(n1.Norm()>EPS); - n1.Normalize(); - typename MESH_TYPE::ScalarType cosa0=n0*n; - typename MESH_TYPE::ScalarType cosa1=n1*n; - if(2-cosa0-cosa1V(ep.z)->P()+ep.f->V1(ep.z)->P())/2.0;return;} - typename MESH_TYPE::ScalarType cosb0=(d0*n)/d; - typename MESH_TYPE::ScalarType cosb1=(d1*n)/d; - assert(1+cosa0>EPS); - assert(1+cosa1>EPS); - typename MESH_TYPE::ScalarType delta0=d*(cosb0 +sqrt( ((1-cosb0*cosb0)*(1-cosa0))/(1+cosa0)) ); - typename MESH_TYPE::ScalarType delta1=d*(cosb1 +sqrt( ((1-cosb1*cosb1)*(1-cosa1))/(1+cosa1)) ); - assert(delta0+delta1<2*d); - nv.P()=vp+n*sign*(delta0+delta1)/2.0; - return ; - } - - // Aggiunte in modo grezzo le due wedgeinterp - Color4 WedgeInterp(Color4 &c0, Color4 &c1) - { - Color4 cc; - return cc.lerp(c0,c1,0.5f); - } - - template - TexCoord2 WedgeInterp(TexCoord2 &t0, TexCoord2 &t1) - { - TexCoord2 tmp; - assert(t0.n()== t1.n()); - tmp.n()=t0.n(); - tmp.t()=(t0.t()+t1.t())/2.0; - return tmp; - } - -}; - -/* -Versione Della Midpoint basata sul paper: -S. Karbacher, S. Seeger, G. Hausler -A non linear subdivision scheme for triangle meshes - - Non funziona! - Almeno due problemi: - 1) il verso delle normali influenza il risultato (e.g. si funziona solo se le normali divergono) - Risolvibile controllando se le normali divergono - 2) gli archi vanno calcolati sul piano definito dalla normale interpolata e l'edge. - funziona molto meglio nelle zone di sella e non semplici. - -*/ -template -struct MidPointArcNaive : public std::unary_function< face::Pos , typename MESH_TYPE::CoordType> -{ - typename MESH_TYPE::CoordType operator()(face::Pos ep) - { - - typename MESH_TYPE::CoordType vp = (ep.f->V(ep.z)->P()+ep.f->V1(ep.z)->P())/2.0; - typename MESH_TYPE::CoordType n = (ep.f->V(ep.z)->N()+ep.f->V1(ep.z)->N())/2.0; - n.Normalize(); - typename MESH_TYPE::CoordType d0 = ep.f->V(ep.z)->P() - vp; - typename MESH_TYPE::CoordType d1 = ep.f->V1(ep.z)->P()- vp; - typename MESH_TYPE::ScalarType d=Distance(ep.f->V(ep.z)->P(),ep.f->V1(ep.z)->P())/2.0; - - typename MESH_TYPE::ScalarType cosa0=ep.f->V(ep.z)->N()*n; - typename MESH_TYPE::ScalarType cosa1=ep.f->V1(ep.z)->N()*n; - typename MESH_TYPE::ScalarType cosb0=(d0*n)/d; - typename MESH_TYPE::ScalarType cosb1=(d1*n)/d; - - typename MESH_TYPE::ScalarType delta0=d*(cosb0 +sqrt( ((1-cosb0*cosb0)*(1-cosa0))/(1+cosa0)) ); - typename MESH_TYPE::ScalarType delta1=d*(cosb1 +sqrt( ((1-cosb1*cosb1)*(1-cosa1))/(1+cosa1)) ); - - return vp+n*(delta0+delta1)/2.0; - } -}; - - -// Basic Predicate that tells if a given edge must be splitted. -// the constructure requires the threshold. -// VERY IMPORTANT REQUIREMENT: this function must be symmetric -// e.g. it must return the same value if the Pos is VFlipped. -// If this function is not symmetric the Refine can crash. - -template -class EdgeLen -{ - FLT squaredThr; -public: - EdgeLen(){}; - EdgeLen(FLT threshold) {setThr(threshold);} - void setThr(FLT threshold) {squaredThr = threshold*threshold; } - bool operator()(face::Pos ep) const - { - return SquaredDistance(ep.V()->P(), ep.VFlip()->P())>squaredThr; - } -}; - -/*********************************************************/ -/********************************************************* - -Given a mesh the following function refines it according to two functor objects: - -- a predicate that tells if a given edge must be splitted - -- a functor that gives you the new poistion of the created vertices (starting from an edge) - -If RefineSelected is true only selected faces are taken into account for being splitted. - -Requirement: FF Adjacency and Manifoldness - -**********************************************************/ -/*********************************************************/ -template -class RefinedFaceData - { - public: - RefinedFaceData(){ - ep[0]=0;ep[1]=0;ep[2]=0; - vp[0]=0;vp[1]=0;vp[2]=0; - } - bool ep[3]; - VertexPointer vp[3]; - }; - -template -bool RefineE(MESH_TYPE &m, MIDPOINT mid, EDGEPRED ep,bool RefineSelected=false, CallBackPos *cb = 0) -{ - // common typenames - typedef typename MESH_TYPE::VertexIterator VertexIterator; - typedef typename MESH_TYPE::FaceIterator FaceIterator; - typedef typename MESH_TYPE::VertexPointer VertexPointer; - typedef typename MESH_TYPE::FacePointer FacePointer; - typedef typename MESH_TYPE::FaceType FaceType; - typedef typename MESH_TYPE::FaceType::TexCoordType TexCoordType; - - typedef face::Pos PosType; - - int j,NewVertNum=0,NewFaceNum=0; - - typedef RefinedFaceData RFD; - typedef typename MESH_TYPE :: template PerFaceAttributeHandle HandleType; - HandleType RD = tri::Allocator:: template AddPerFaceAttribute (m,std::string("RefineData")); - - // Callback stuff - int step=0; - int PercStep=std::max(1,m.fn/33); - - // First Loop: We analyze the mesh to compute the number of the new faces and new vertices - FaceIterator fi; - for(fi=m.face.begin(),j=0;fi!=m.face.end();++fi) if(!(*fi).IsD()) - { - if(cb && (++step%PercStep)==0) (*cb)(step/PercStep,"Refining..."); - // skip unselected faces if necessary - if(RefineSelected && !(*fi).IsS()) continue; - - for(j=0;j<3;j++) - { - if(RD[fi].ep[j]) continue; - - PosType edgeCur(&*fi,j); - if(RefineSelected && ! edgeCur.FFlip()->IsS()) continue; - if(!ep(edgeCur)) continue; - - RD[edgeCur.F()].ep[edgeCur.E()]=true; - ++NewFaceNum; - ++NewVertNum; - assert(edgeCur.IsManifold()); - if(!edgeCur.IsBorder()) - { - edgeCur.FlipF(); - edgeCur.F()->SetV(); - RD[edgeCur.F()].ep[edgeCur.E()]=true; - ++NewFaceNum; - } - } - - } // end face loop - - if(NewVertNum ==0 ) - { - tri::Allocator :: template DeletePerFaceAttribute > (m,RD); - return false; - } - VertexIterator lastv = tri::Allocator::AddVertices(m,NewVertNum); - - // Secondo loop: We initialize a edge->vertex map - - for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) - { - if(cb && (++step%PercStep)==0)(*cb)(step/PercStep,"Refining..."); - for(j=0;j<3;j++) - { - // skip unselected faces if necessary - if(RefineSelected && !(*fi).IsS()) continue; - for(j=0;j<3;j++) - { - PosType edgeCur(&*fi,j); - if(RefineSelected && ! edgeCur.FFlip()->IsS()) continue; - - if( RD[edgeCur.F()].ep[edgeCur.E()] && RD[edgeCur.F()].vp[edgeCur.E()] ==0 ) - { - RD[edgeCur.F()].vp[edgeCur.E()] = &*lastv; - mid(*lastv,edgeCur); - if(!edgeCur.IsBorder()) - { - edgeCur.FlipF(); - assert(RD[edgeCur.F()].ep[edgeCur.E()]); - RD[edgeCur.F()].vp[edgeCur.E()] = &*lastv; - } - ++lastv; - } - } - } - } - - assert(lastv==m.vert.end()); // critical assert: we MUST have used all the vertex that we forecasted we need - - FaceIterator lastf = tri::Allocator::AddFaces(m,NewFaceNum); - FaceIterator oldendf = lastf; - -/* - v0 - - - f0 - - mp01 f3 mp02 - - - f1 f2 - - v1 mp12 v2 - -*/ - - VertexPointer vv[6]; // The six vertices that arise in the single triangle splitting - // 0..2 Original triangle vertices - // 3..5 mp01, mp12, mp20 midpoints of the three edges - FacePointer nf[4]; // The (up to) four faces that are created. - - TexCoordType wtt[6]; // per ogni faccia sono al piu' tre i nuovi valori - // di texture per wedge (uno per ogni edge) - - int fca=0,fcn =0; - for(fi=m.face.begin();fi!=oldendf;++fi) if(!(*fi).IsD()) - { - if(cb && (++step%PercStep)==0)(*cb)(step/PercStep,"Refining..."); - fcn++; - vv[0]=(*fi).V(0); - vv[1]=(*fi).V(1); - vv[2]=(*fi).V(2); - vv[3] = RD[fi].vp[0]; - vv[4] = RD[fi].vp[1]; - vv[5] = RD[fi].vp[2]; - - int ind=((&*vv[3])?1:0)+((&*vv[4])?2:0)+((&*vv[5])?4:0); - - nf[0]=&*fi; - int i; - for(i=1;iC()=(*fi).cC(); - } - - - if(tri::HasPerWedgeTexCoord(m)) - for(i=0;i<3;++i) { - wtt[i]=(*fi).WT(i); - wtt[3+i]=mid.WedgeInterp((*fi).WT(i),(*fi).WT((i+1)%3)); - } - - int orgflag= (*fi).UberFlags(); - for(i=0;iP(),vv[SplitTab[ind].swap[0][1]]->P()) < - SquaredDistance(vv[SplitTab[ind].swap[1][0]]->P(),vv[SplitTab[ind].swap[1][1]]->P()) ) - { // swap the last two triangles - (*nf[2]).V(1)=(*nf[1]).V(0); - (*nf[1]).V(1)=(*nf[2]).V(0); - if(tri::HasPerWedgeTexCoord(m)){ //swap also textures coordinates - (*nf[2]).WT(1)=(*nf[1]).WT(0); - (*nf[1]).WT(1)=(*nf[2]).WT(0); - } - - if((*nf[1]).IsB(0)) (*nf[2]).SetB(1); else (*nf[2]).ClearB(1); - if((*nf[2]).IsB(0)) (*nf[1]).SetB(1); else (*nf[1]).ClearB(1); - (*nf[1]).ClearB(0); - (*nf[2]).ClearB(0); - } - } - - assert(lastf==m.face.end()); // critical assert: we MUST have used all the faces that we forecasted we need and that we previously allocated. - assert(!m.vert.empty()); - for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()){ - assert((*fi).V(0)>=&*m.vert.begin() && (*fi).V(0)<=&m.vert.back() ); - assert((*fi).V(1)>=&*m.vert.begin() && (*fi).V(1)<=&m.vert.back() ); - assert((*fi).V(2)>=&*m.vert.begin() && (*fi).V(2)<=&m.vert.back() ); - } - tri::UpdateTopology::FaceFace(m); - - tri::Allocator :: template DeletePerFaceAttribute > (m,RD); - - return true; -} - -/*************************************************************************/ -// simple wrapper of the base refine for lazy coder that do not need a edge predicate - -template -bool Refine(MESH_TYPE &m, MIDPOINT mid, typename MESH_TYPE::ScalarType thr=0,bool RefineSelected=false, CallBackPos *cb = 0) -{ - EdgeLen ep(thr); - return RefineE(m,mid,ep,RefineSelected,cb); -} -/*************************************************************************/ - -/* -Modified Butterfly interpolation scheme, -as presented in -Zorin, Schroeder -Subdivision for modeling and animation -Siggraph 2000 Course Notes -*/ - -/* - - vul-------vu--------vur - \ / \ / - \ / \ / - \ / fu \ / - vl--------vr - / \ fd / \ - / \ / \ - / \ / \ - vdl-------vd--------vdr - -*/ - -template -struct MidPointButterfly : public std::unary_function , typename MESH_TYPE::CoordType> -{ - void operator()(typename MESH_TYPE::VertexType &nv, face::Pos ep) - { - face::Pos he(ep.f,ep.z,ep.f->V(ep.z)); - typename MESH_TYPE::CoordType *vl,*vr; - typename MESH_TYPE::CoordType *vl0,*vr0; - typename MESH_TYPE::CoordType *vu,*vd,*vul,*vur,*vdl,*vdr; - vl=&he.v->P(); - he.FlipV(); - vr=&he.v->P(); - - if( MESH_TYPE::HasPerVertexColor()) - nv.C().lerp(ep.f->V(ep.z)->C(),ep.f->V1(ep.z)->C(),.5f); - - if(he.IsBorder()) - { - he.NextB(); - vr0=&he.v->P(); - he.FlipV(); - he.NextB(); - assert(&he.v->P()==vl); - he.NextB(); - vl0=&he.v->P(); - nv.P()=((*vl)+(*vr))*(9.0/16.0)-((*vl0)+(*vr0))/16.0 ; - } - else - { - he.FlipE();he.FlipV(); - vu=&he.v->P(); - he.FlipF();he.FlipE();he.FlipV(); - vur=&he.v->P(); - he.FlipV();he.FlipE();he.FlipF(); assert(&he.v->P()==vu); // back to vu (on the right) - he.FlipE(); - he.FlipF();he.FlipE();he.FlipV(); - vul=&he.v->P(); - he.FlipV();he.FlipE();he.FlipF(); assert(&he.v->P()==vu); // back to vu (on the left) - he.FlipV();he.FlipE();he.FlipF(); assert(&he.v->P()==vl);// again on vl (but under the edge) - he.FlipE();he.FlipV(); - vd=&he.v->P(); - he.FlipF();he.FlipE();he.FlipV(); - vdl=&he.v->P(); - he.FlipV();he.FlipE();he.FlipF(); assert(&he.v->P()==vd);// back to vd (on the right) - he.FlipE(); - he.FlipF();he.FlipE();he.FlipV(); - vdr=&he.v->P(); - - nv.P()=((*vl)+(*vr))/2.0+((*vu)+(*vd))/8.0 - ((*vul)+(*vur)+(*vdl)+(*vdr))/16.0; - } - } - - /// Aggiunte in modo grezzo le due wedge interp - Color4 WedgeInterp(Color4 &c0, Color4 &c1) - { - Color4 cc; - return cc.lerp(c0,c1,0.5f); - } - - template - TexCoord2 WedgeInterp(TexCoord2 &t0, TexCoord2 &t1) - { - TexCoord2 tmp; - assert(t0.n()== t1.n()); - tmp.n()=t0.n(); - tmp.t()=(t0.t()+t1.t())/2.0; - return tmp; - } -}; - - -#if 0 - int rule=0; - if(vr==vul) rule+=1; - if(vl==vur) rule+=2; - if(vl==vdr) rule+=4; - if(vr==vdl) rule+=8; - switch(rule){ -/* */ -/* */ case 0 : return ((*vl)+(*vr))/2.0+((*vu)+(*vd))/8.0 - ((*vul)+(*vur)+(*vdl)+(*vdr))/16.0; -/* ul */ case 1 : return (*vl*6 + *vr*10 + *vu + *vd*3 - *vur - *vdl -*vdr*2 )/16.0; -/* ur */ case 2 : return (*vr*6 + *vl*10 + *vu + *vd*3 - *vul - *vdr -*vdl*2 )/16.0; -/* dr */ case 4 : return (*vr*6 + *vl*10 + *vd + *vu*3 - *vdl - *vur -*vul*2 )/16.0; -/* dl */ case 8 : return (*vl*6 + *vr*10 + *vd + *vu*3 - *vdr - *vul -*vur*2 )/16.0; -/* ul,ur */ case 3 : return (*vl*4 + *vr*4 + *vd*2 + - *vdr - *vdl )/8.0; -/* dl,dr */ case 12 : return (*vl*4 + *vr*4 + *vu*2 + - *vur - *vul )/8.0; - -/* ul,dr */ case 5 : -/* ur,dl */ case 10 : - default: - return (*vl+ *vr)/2.0; - } - - - -#endif -/* - vul-------vu--------vur - \ / \ / - \ / \ / - \ / fu \ / - vl--------vr - / \ fd / \ - / \ / \ - / \ / \ - vdl-------vd--------vdr - -*/ - -// Versione modificata per tenere di conto in meniara corretta dei vertici con valenza alta - -template -struct MidPointButterfly2 : public std::unary_function , typename MESH_TYPE::CoordType> -{ - typename MESH_TYPE::CoordType operator()(face::Pos ep) - { -double Rules[11][10] = -{ - {.0}, // valenza 0 - {.0}, // valenza 1 - {.0}, // valenza 2 - { .4166666667, -.08333333333 , -.08333333333 }, // valenza 3 - { .375 , .0 , -0.125 , .0 }, // valenza 4 - { .35 , .03090169945 , -.08090169945 , -.08090169945, .03090169945 }, // valenza 5 - { .5 , .125 , -0.0625 , .0 , -0.0625 , 0.125 }, // valenza 6 - { .25 , .1088899050 , -.06042933822 , -.04846056675, -.04846056675, -.06042933822, .1088899050 }, // valenza 7 - { .21875 , .1196383476 , -.03125 , -.05713834763, -.03125 , -.05713834763, -.03125 ,.1196383476 }, // valenza 8 - { .1944444444, .1225409480 , -.00513312590 , -.05555555556, -.03407448880, -.03407448880, -.05555555556, -.00513312590, .1225409480 }, // valenza 9 - { .175 , .1213525492 , .01545084973 , -.04635254918, -.04045084973, -.025 , -.04045084973, -.04635254918, .01545084973, .1213525492 } // valenza 10 -}; - -face::Pos he(ep.f,ep.z,ep.f->V(ep.z)); - typename MESH_TYPE::CoordType *vl,*vr; - vl=&he.v->P(); - vr=&he.VFlip()->P(); - if(he.IsBorder()) - {he.FlipV(); - typename MESH_TYPE::CoordType *vl0,*vr0; - he.NextB(); - vr0=&he.v->P(); - he.FlipV(); - he.NextB(); - assert(&he.v->P()==vl); - he.NextB(); - vl0=&he.v->P(); - return ((*vl)+(*vr))*(9.0/16.0)-((*vl0)+(*vr0))/16.0 ; - } - - int kl=0,kr=0; // valence of left and right vertices - bool bl=false,br=false; // if left and right vertices are of border - face::Pos heStart=he;assert(he.v->P()==*vl); - do { // compute valence of left vertex - he.FlipE();he.FlipF(); - if(he.IsBorder()) bl=true; - ++kl; - } while(he!=heStart); - - he.FlipV();heStart=he;assert(he.v->P()==*vr); - do { // compute valence of right vertex - he.FlipE();he.FlipF(); - if(he.IsBorder()) br=true; - ++kr; - } while(he!=heStart); - if(br||bl) return MidPointButterfly()( ep ); - if(kr==6 && kl==6) return MidPointButterfly()( ep ); - // TRACE("odd vertex among valences of %i %i\n",kl,kr); - typename MESH_TYPE::CoordType newposl=*vl*.75, newposr=*vr*.75; - he.FlipV();heStart=he; assert(he.v->P()==*vl); - int i=0; - if(kl!=6) - do { // compute position of left vertex - newposl+= he.VFlip()->P() * Rules[kl][i]; - he.FlipE();he.FlipF(); - ++i; - } while(he!=heStart); - i=0;he.FlipV();heStart=he;assert(he.v->P()==*vr); - if(kr!=6) - do { // compute position of right vertex - newposr+=he.VFlip()->P()* Rules[kr][i]; - he.FlipE();he.FlipF(); - ++i; - } while(he!=heStart); - if(kr==6) return newposl; - if(kl==6) return newposr; - return newposl+newposr; - } -}; - -/* -// Nuovi punti (e.g. midpoint) -template -struct OddPointLoop : public std::unary_function , typename MESH_TYPE::CoordType> -{ - - -} - -// vecchi punti -template -struct EvenPointLoop : public std::unary_function , typename MESH_TYPE::CoordType> -{ -} -*/ - -template -struct MidPointPlane : public std::unary_function , typename MESH_TYPE::CoordType> -{ - Plane3 pl; - typedef Point3 Point3x; - - void operator()(typename MESH_TYPE::VertexType &nv, face::Pos ep){ - Point3x &p0=ep.f->V0(ep.z)->P(); - Point3x &p1=ep.f->V1(ep.z)->P(); - double pp= Distance(p0,pl)/(Distance(p0,pl) - Distance(p1,pl)); - - nv.P()=p1*pp + p0*(1.0-pp); - } - - Color4 WedgeInterp(Color4 &c0, Color4 &c1) - { - Color4 cc; - return cc.lerp(c0,c1,0.5f); - } - - template - TexCoord2 WedgeInterp(TexCoord2 &t0, TexCoord2 &t1) - { - TexCoord2 tmp; - assert(t0.n()== t1.n()); - tmp.n()=t0.n(); - tmp.t()=(t0.t()+t1.t())/2.0; - return tmp; - } -}; - - -template -class EdgeSplPlane -{ - public: - Plane3 pl; - bool operator()(const Point3 &p0, const Point3 &p1) const - { - if(Distance(pl,p0)>0) { - if(Distance(pl,p1)>0) return false; - else return true; - } - else if(Distance(pl,p1)<=0) return false; - return true; - } -}; - - -template -struct MidPointSphere : public std::unary_function , typename MESH_TYPE::CoordType> -{ - Sphere3 sph; - typedef Point3 Point3x; - - void operator()(typename MESH_TYPE::VertexType &nv, face::Pos ep){ - Point3x &p0=ep.f->V0(ep.z)->P(); - Point3x &p1=ep.f->V1(ep.z)->P(); - nv.P()= sph.c+((p0+p1)/2.0 - sph.c ).Normalize(); - } - - Color4 WedgeInterp(Color4 &c0, Color4 &c1) - { - Color4 cc; - return cc.lerp(c0,c1,0.5f); - } - - template - TexCoord2 WedgeInterp(TexCoord2 &t0, TexCoord2 &t1) - { - TexCoord2 tmp; - assert(t0.n()== t1.n()); - tmp.n()=t0.n(); - tmp.t()=(t0.t()+t1.t())/2.0; - return tmp; - } -}; - - -template -class EdgeSplSphere -{ - public: - Sphere3 sph; - bool operator()(const Point3 &p0, const Point3 &p1) const - { - if(Distance(sph,p0)>0) { - if(Distance(sph,p1)>0) return false; - else return true; - } - else if(Distance(sph,p1)<=0) return false; - return true; - } -}; - -/*! -* Triangle split -*/ - -template -struct CenterPoint : public std::unary_function -{ - typename TRIMESH_TYPE::CoordType operator()(typename TRIMESH_TYPE::FacePointer f){ - return vcg::Barycenter(*f); - } -}; - -template -void TriSplit(typename TRIMESH_TYPE::FacePointer f, - typename TRIMESH_TYPE::FacePointer f1,typename TRIMESH_TYPE::FacePointer f2, - typename TRIMESH_TYPE::VertexPointer vB, CenterPoint Center) -{ - vB->P() = Center(f); - - //i tre vertici della faccia da dividere - typename TRIMESH_TYPE::VertexType* V0,*V1,*V2; - V0 = f->V(0); - V1 = f->V(1); - V2 = f->V(2); - - //risistemo la faccia di partenza - (*f).V(2) = &(*vB); - //Faccia nuova #1 - (*f1).V(0) = &(*vB); - (*f1).V(1) = V1; - (*f1).V(2) = V2; - //Faccia nuova #2 - (*f2).V(0) = V0; - (*f2).V(1) = &(*vB); - (*f2).V(2) = V2; - - if(f->HasFFAdjacency()) - { - //adiacenza delle facce adiacenti a quelle aggiunte - f->FFp(1)->FFp(f->FFi(1)) = f1; - f->FFp(2)->FFp(f->FFi(2)) = f2; - - //adiacenza ff - typename TRIMESH_TYPE::FacePointer FF0,FF1,FF2; - FF0 = f->FFp(0); - FF1 = f->FFp(1); - FF2 = f->FFp(2); - - //Indici di adiacenza ff - char FFi0,FFi1,FFi2; - FFi0 = f->FFi(0); - FFi1 = f->FFi(1); - FFi2 = f->FFi(2); - - //adiacenza della faccia di partenza - (*f).FFp(1) = &(*f1); - (*f).FFi(1) = 0; - (*f).FFp(2) = &(*f2); - (*f).FFi(2) = 0; - - //adiacenza della faccia #1 - (*f1).FFp(0) = f; - (*f1).FFi(0) = 1; - - (*f1).FFp(1) = FF1; - (*f1).FFi(1) = FFi1; - - (*f1).FFp(2) = &(*f2); - (*f1).FFi(2) = 1; - - //adiacenza della faccia #2 - (*f2).FFp(0) = f; - (*f2).FFi(0) = 2; - - (*f2).FFp(1) = &(*f1); - (*f2).FFi(1) = 2; - - (*f2).FFp(2) = FF2; - (*f2).FFi(2) = FFi2; - } -} - - -} // namespace vcg - - - - -#endif diff --git a/vcg/complex/trimesh/refine_loop.h b/vcg/complex/trimesh/refine_loop.h deleted file mode 100644 index 180a540c..00000000 --- a/vcg/complex/trimesh/refine_loop.h +++ /dev/null @@ -1,623 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ -/*! \file refine_loop.h - * - * \brief This file contain code for Loop's subdivision scheme for triangular - * mesh and some similar method. - * - */ - -#ifndef __VCGLIB_REFINE_LOOP -#define __VCGLIB_REFINE_LOOP - -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace vcg{ -namespace tri{ - -/* -Metodo di Loop dalla documentazione "Siggraph 2000 course on subdivision" - - d4------d3 d4------d3 - / \ / \ / \ / \ u - / \ / \ / e4--e3 \ / \ - / \/ \ / / \/ \ \ / \ -d5------d1------d2 -> d5--e5--d1--e2--d2 l--M--r - \ /\ / \ \ /\ / / \ / - \ / \ / \ e6--e7 / \ / - \ / \ / \ / \ / d - d6------d7 d6------d7 - -******************************************************* - -*/ - -/*! - * \brief Weight class for classical Loop's scheme. - * - * See Zorin, D. & Schröeder, P.: Subdivision for modeling and animation. Proc. ACM SIGGRAPH [Courses], 2000 - */ -template -struct LoopWeight { - inline SCALAR_TYPE beta(int k) { - return (k>3)?(5.0/8.0 - std::pow((3.0/8.0 + std::cos(2.0*M_PI/SCALAR_TYPE(k))/4.0),2))/SCALAR_TYPE(k):3.0/16.0; - } - - inline SCALAR_TYPE incidentRegular(int) { - return 3.0/8.0; - } - inline SCALAR_TYPE incidentIrregular(int) { - return 3.0/8.0; - } - inline SCALAR_TYPE opposite(int) { - return 1.0/8.0; - } -}; - -/*! - * \brief Modified Loop's weight to optimise continuity. - * - * See Barthe, L. & Kobbelt, L.: Subdivision scheme tuning around extraordinary vertices. Computer Aided Geometric Design, 2004, 21, 561-583 - */ -template -struct RegularLoopWeight { - inline SCALAR_TYPE beta(int k) { - static SCALAR_TYPE bkPolar[] = { - .32517, - .49954, - .59549, - .625, - .63873, - .64643, - .65127, - .67358, - .68678, - .69908 - }; - - return (k<=12)?(1.0-bkPolar[k-3])/k:LoopWeight().beta(k); - } - - inline SCALAR_TYPE incidentRegular(int k) { - return 1.0 - incidentIrregular(k) - opposite(k)*2; - } - inline SCALAR_TYPE incidentIrregular(int k) { - static SCALAR_TYPE bkPolar[] = { - .15658, - .25029, - .34547, - .375, - .38877, - .39644, - .40132, - .42198, - .43423, - .44579 - }; - - return (k<=12)?bkPolar[k-3]:LoopWeight().incidentIrregular(k); - } - inline SCALAR_TYPE opposite(int k) { - static SCALAR_TYPE bkPolar[] = { - .14427, - .12524, - .11182, - .125, - .14771, - .1768, - .21092, - .20354, - .20505, - .19828 - }; - - return (k<=12)?bkPolar[k-3]:LoopWeight().opposite(k); - } -}; - -template -struct ContinuityLoopWeight { - inline SCALAR_TYPE beta(int k) { - static SCALAR_TYPE bkPolar[] = { - .32517, - .50033, - .59464, - .625, - .63903, - .67821, - .6866, - .69248, - .69678, - .70014 - }; - - return (k<=12)?(1.0-bkPolar[k-3])/k:LoopWeight().beta(k); - } - - inline SCALAR_TYPE incidentRegular(int k) { - return 1.0 - incidentIrregular(k) - opposite(k)*2; - } - inline SCALAR_TYPE incidentIrregular(int k) { - static SCALAR_TYPE bkPolar[] = { - .15658, - .26721, - .33539, - .375, - .36909, - .25579, - .2521, - .24926, - .24706, - .2452 - }; - - return (k<=12)?bkPolar[k-3]:LoopWeight().incidentIrregular(k); - } - inline SCALAR_TYPE opposite(int k) { - static SCALAR_TYPE bkPolar[] = { - .14427, - .12495, - .11252, - .125, - .14673, - .16074, - .18939, - .2222, - .25894, - .29934 - }; - - return (k<=12)?bkPolar[k-3]:LoopWeight().opposite(k); - } -}; - -// Centroid and LS3Projection classes may be pettre placed in an other file. (which one ?) - -/*! - * \brief Allow to compute classical Loop subdivision surface with the same code than LS3. - */ -template -struct Centroid { - typedef typename MESH_TYPE::ScalarType Scalar; - typedef typename MESH_TYPE::CoordType Coord; - typedef LSCALAR_TYPE LScalar; - typedef vcg::Point3 LVector; - - LVector sumP; - LScalar sumW; - - Centroid() { reset(); } - inline void reset() { - sumP.SetZero(); - sumW = 0.; - } - inline void addVertex(const typename MESH_TYPE::VertexType &v, LScalar w) { - LVector p(v.cP().X(), v.cP().Y(), v.cP().Z()); - LVector n(v.cN().X(), v.cN().Y(), v.cN().Z()); - - sumP += p * w; - sumW += w; - } - inline void project(typename MESH_TYPE::VertexType &v) const { - LVector position = sumP / sumW; - v.P() = Coord(position.X(), position.Y(), position.Z()); - } -}; - -/*! Implementation of the APSS projection for the LS3 scheme. - * - * See Gael Guennebaud and Marcel Germann and Markus Gross - * Dynamic sampling and rendering of algebraic point set surfaces. - * Computer Graphics Forum (Proceedings of Eurographics 2008), 2008, 27, 653-662 - * and Simon Boye and Gael Guennebaud and Christophe Schlick - * Least squares subdivision surfaces - * Computer Graphics Forum, 2010 - */ -template -struct LS3Projection { - typedef typename MESH_TYPE::ScalarType Scalar; - typedef typename MESH_TYPE::CoordType Coord; - typedef LSCALAR_TYPE LScalar; - typedef vcg::Point3 LVector; - - Scalar beta; - - LVector sumP; - LVector sumN; - LScalar sumDotPN; - LScalar sumDotPP; - LScalar sumW; - - inline LS3Projection(Scalar beta = 1.0) : beta(beta) { reset(); } - inline void reset() { - sumP.SetZero(); - sumN.SetZero(); - sumDotPN = 0.; - sumDotPP = 0.; - sumW = 0.; - } - inline void addVertex(const typename MESH_TYPE::VertexType &v, LScalar w) { - LVector p(v.cP().X(), v.cP().Y(), v.cP().Z()); - LVector n(v.cN().X(), v.cN().Y(), v.cN().Z()); - - sumP += p * w; - sumN += n * w; - sumDotPN += w * n.dot(p); - sumDotPP += w * vcg::SquaredNorm(p); - sumW += w; - } - void project(typename MESH_TYPE::VertexType &v) const { - LScalar invSumW = Scalar(1)/sumW; - LScalar aux4 = beta * LScalar(0.5) * - (sumDotPN - invSumW*sumP.dot(sumN)) - /(sumDotPP - invSumW*vcg::SquaredNorm(sumP)); - LVector uLinear = (sumN-sumP*(Scalar(2)*aux4))*invSumW; - LScalar uConstant = -invSumW*(uLinear.dot(sumP) + sumDotPP*aux4); - LScalar uQuad = aux4; - LVector orig = sumP*invSumW; - - // finalize - LVector position; - LVector normal; - if (fabs(uQuad)>1e-7) - { - LScalar b = 1./uQuad; - LVector center = uLinear*(-0.5*b); - LScalar radius = sqrt( vcg::SquaredNorm(center) - b*uConstant ); - - normal = orig - center; - normal.Normalize(); - position = center + normal * radius; - - normal = uLinear + position * (LScalar(2) * uQuad); - normal.Normalize(); - } - else if (uQuad==0.) - { - LScalar s = LScalar(1)/vcg::Norm(uLinear); - assert(!vcg::math::IsNAN(s) && "normal should not have zero len!"); - uLinear *= s; - uConstant *= s; - - normal = uLinear; - position = orig - uLinear * (orig.dot(uLinear) + uConstant); - } - else - { - // normalize the gradient - LScalar f = 1./sqrt(vcg::SquaredNorm(uLinear) - Scalar(4)*uConstant*uQuad); - uConstant *= f; - uLinear *= f; - uQuad *= f; - - // Newton iterations - LVector grad; - LVector dir = uLinear+orig*(2.*uQuad); - LScalar ilg = 1./vcg::Norm(dir); - dir *= ilg; - LScalar ad = uConstant + uLinear.dot(orig) + uQuad * vcg::SquaredNorm(orig); - LScalar delta = -ad*std::min(ilg,1.); - LVector p = orig + dir*delta; - for (int i=0 ; i<2 ; ++i) - { - grad = uLinear+p*(2.*uQuad); - ilg = 1./vcg::Norm(grad); - delta = -(uConstant + uLinear.dot(p) + uQuad * vcg::SquaredNorm(p))*std::min(ilg,1.); - p += dir*delta; - } - position = p; - - normal = uLinear + position * (Scalar(2) * uQuad); - normal.Normalize(); - } - - v.P() = Coord(position.X(), position.Y(), position.Z()); - v.N() = Coord(normal.X(), normal.Y(), normal.Z()); - } -}; - -template, class WEIGHT_TYPE=LoopWeight > -struct OddPointLoopGeneric : public std::unary_function , typename MESH_TYPE::VertexType> -{ - typedef METHOD_TYPE Projection; - typedef WEIGHT_TYPE Weight; - typedef typename MESH_TYPE::template PerVertexAttributeHandle ValenceAttr; - - Projection proj; - Weight weight; - ValenceAttr *valence; - - inline OddPointLoopGeneric(Projection proj = Projection(), Weight weight = Weight()) : - proj(proj), weight(weight), valence(0) {} - - void operator()(typename MESH_TYPE::VertexType &nv, face::Pos ep) { - proj.reset(); - - face::Pos he(ep.f,ep.z,ep.f->V(ep.z)); - typename MESH_TYPE::VertexType *l,*r,*u,*d; - l = he.v; - he.FlipV(); - r = he.v; - - if( MESH_TYPE::HasPerVertexColor()) - nv.C().lerp(ep.f->V(ep.z)->C(),ep.f->V1(ep.z)->C(),.5f); - - if (he.IsBorder()) { - proj.addVertex(*l, 0.5); - proj.addVertex(*r, 0.5); - proj.project(nv); - } - else { - he.FlipE(); he.FlipV(); - u = he.v; - he.FlipV(); he.FlipE(); - assert(he.v == r); // back to r - he.FlipF(); he.FlipE(); he.FlipV(); - d = he.v; - - if(valence && ((*valence)[l]==6 || (*valence)[r]==6)) { - int extra = ((*valence)[l]==6)?(*valence)[r]:(*valence)[l]; - proj.addVertex(*l, ((*valence)[l]==6)?weight.incidentRegular(extra):weight.incidentIrregular(extra)); - proj.addVertex(*r, ((*valence)[r]==6)?weight.incidentRegular(extra):weight.incidentIrregular(extra)); - proj.addVertex(*u, weight.opposite(extra)); - proj.addVertex(*d, weight.opposite(extra)); - } - // unhandled case that append only at first subdivision step: use Loop's weights - else { - proj.addVertex(*l, 3.0/8.0); - proj.addVertex(*r, 3.0/8.0); - proj.addVertex(*u, 1.0/8.0); - proj.addVertex(*d, 1.0/8.0); - } - proj.project(nv); - } - - } - - Color4 WedgeInterp(Color4 &c0, Color4 &c1) - { - Color4 cc; - return cc.lerp(c0,c1,0.5f); - } - - template - TexCoord2 WedgeInterp(TexCoord2 &t0, TexCoord2 &t1) - { - TexCoord2 tmp; - tmp.n()=t0.n(); - tmp.t()=(t0.t()+t1.t())/2.0; - return tmp; - } - - inline void setValenceAttr(ValenceAttr *valence) { - this->valence = valence; - } -}; - -template, class WEIGHT_TYPE=LoopWeight > -struct EvenPointLoopGeneric : public std::unary_function , typename MESH_TYPE::VertexType> -{ - typedef METHOD_TYPE Projection; - typedef WEIGHT_TYPE Weight; - typedef typename MESH_TYPE::template PerVertexAttributeHandle ValenceAttr; - - Projection proj; - Weight weight; - ValenceAttr *valence; - - inline EvenPointLoopGeneric(Projection proj = Projection(), Weight weight = Weight()) : - proj(proj), weight(weight), valence(0) {} - - void operator()(typename MESH_TYPE::VertexType &nv, face::Pos ep) { - proj.reset(); - - face::Pos he(ep.f,ep.z,ep.f->V(ep.z)); - typename MESH_TYPE::VertexType *r, *l, *curr; - curr = he.v; - face::Pos heStart = he; - - // compute valence of this vertex or find a border - int k = 0; - do { - he.NextE(); - k++; - } while(!he.IsBorder() && he != heStart); - - if (he.IsBorder()) { // Border rule - // consider valence of borders as if they are half+1 of an inner vertex. not perfect, but better than nothing. - if(valence) { - k = 0; - do { - he.NextE(); - k++; - } while(!he.IsBorder()); - (*valence)[he.V()] = std::max(2*(k-1), 3); -// (*valence)[he.V()] = 6; - } - - he.FlipV(); - r = he.v; - he.FlipV(); - he.NextB(); - l = he.v; - - proj.addVertex(*curr, 3.0/4.0); - proj.addVertex(*l, 1.0/8.0); - proj.addVertex(*r, 1.0/8.0); - proj.project(nv); - } - else { // Inner rule -// assert(!he.v->IsB()); border flag no longer updated (useless) - if(valence) - (*valence)[he.V()] = k; - - typename MESH_TYPE::ScalarType beta = weight.beta(k); - - proj.addVertex(*curr, 1.0 - (typename MESH_TYPE::ScalarType)(k) * beta); - do { - proj.addVertex(*he.VFlip(), beta); - he.NextE(); - } while(he != heStart); - - proj.project(nv); - } - } // end of operator() - - Color4 WedgeInterp(Color4 &c0, Color4 &c1) - { - Color4 cc; - return cc.lerp(c0,c1,0.5f); - } - Color4b WedgeInterp(Color4b &c0, Color4b &c1) - { - Color4b cc; - cc.lerp(c0,c1,0.5f); - return cc; - } - - template - TexCoord2 WedgeInterp(TexCoord2 &t0, TexCoord2 &t1) - { - TexCoord2 tmp; - // assert(t0.n()== t1.n()); - tmp.n()=t0.n(); - tmp.t()=(t0.t()+t1.t())/2.0; - return tmp; - } - - inline void setValenceAttr(ValenceAttr *valence) { - this->valence = valence; - } -}; - -template -struct OddPointLoop : OddPointLoopGeneric > -{ -}; - -template -struct EvenPointLoop : EvenPointLoopGeneric > -{ -}; - -template -bool RefineOddEven(MESH_TYPE &m, ODD_VERT odd, EVEN_VERT even,float length, - bool RefineSelected=false, CallBackPos *cbOdd = 0, CallBackPos *cbEven = 0) -{ - EdgeLen ep(length); - return RefineOddEvenE(m, odd, even, ep, RefineSelected, cbOdd, cbEven); -} - -/*! - * \brief Perform diadic subdivision using given rules for odd and even vertices. - */ -template -bool RefineOddEvenE(MESH_TYPE &m, ODD_VERT odd, EVEN_VERT even, PREDICATE edgePred, - bool RefineSelected=false, CallBackPos *cbOdd = 0, CallBackPos *cbEven = 0) -{ - typedef typename MESH_TYPE::template PerVertexAttributeHandle ValenceAttr; - - // momentaneamente le callback sono identiche, almeno cbOdd deve essere passata - cbEven = cbOdd; - - // to mark visited vertices - int evenFlag = MESH_TYPE::VertexType::NewBitFlag(); - for (int i = 0; i < m.vn ; i++ ) { - m.vert[i].ClearUserBit(evenFlag); - } - - int j = 0; - // di texture per wedge (uno per ogni edge) - - ValenceAttr valence = vcg::tri::Allocator:: template AddPerVertexAttribute(m); - odd.setValenceAttr(&valence); - even.setValenceAttr(&valence); - - // store updated vertices - std::vector updatedList(m.vn, false); - std::vector newEven(m.vn); - - typename MESH_TYPE::VertexIterator vi; - typename MESH_TYPE::FaceIterator fi; - for (fi = m.face.begin(); fi != m.face.end(); fi++) if(!(*fi).IsD() && (!RefineSelected || (*fi).IsS())){ //itero facce - for (int i = 0; i < 3; i++) { //itero vert - if ( !(*fi).V(i)->IsUserBit(evenFlag) && ! (*fi).V(i)->IsD() ) { - (*fi).V(i)->SetUserBit(evenFlag); - // use face selection, not vertex selection, to be coherent with RefineE - //if (RefineSelected && !(*fi).V(i)->IsS() ) - // break; - face::Posaux (&(*fi),i); - if( MESH_TYPE::HasPerVertexColor() ) { - (*fi).V(i)->C().lerp((*fi).V0(i)->C() , (*fi).V1(i)->C(),0.5f); - } - - if (cbEven) { - (*cbEven)(int(100.0f * (float)j / (float)m.fn),"Refining"); - j++; - } - int index = tri::Index(m, (*fi).V(i)); - updatedList[index] = true; - even(newEven[index], aux); - } - } - } - - MESH_TYPE::VertexType::DeleteBitFlag(evenFlag); - - // refine dei vertici odd, crea dei nuovi vertici in coda - RefineE< MESH_TYPE, ODD_VERT > (m, odd, edgePred, RefineSelected, cbOdd); - - typename std::vector::iterator nei; - for (nei=newEven.begin(); nei!=newEven.end(); ++nei) { - if(updatedList[nei-newEven.begin()]) { - m.vert[nei-newEven.begin()].ImportData(*nei); - assert(m.vert[nei-newEven.begin()].N() == nei->N()); - } - } - - odd.setValenceAttr(0); - even.setValenceAttr(0); - - vcg::tri::Allocator::DeletePerVertexAttribute(m, valence); - - return true; -} - -} // namespace tri -} // namespace vcg - - - - -#endif - - - diff --git a/vcg/complex/trimesh/smooth.h b/vcg/complex/trimesh/smooth.h deleted file mode 100644 index 909f81a8..00000000 --- a/vcg/complex/trimesh/smooth.h +++ /dev/null @@ -1,1331 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ - - -#ifndef __VCGLIB__SMOOTH -#define __VCGLIB__SMOOTH - -#include -#include -#include -#include -#include -#include -#include - - -namespace vcg -{ -namespace tri -{ -/// -/** \addtogroup trimesh */ -/*@{*/ -/// Class of static functions to smooth and fair meshes and their attributes. - -template -class Smooth -{ - -public: - typedef SmoothMeshType MeshType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::VertexType::CoordType CoordType; - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::FacePointer FacePointer; - typedef typename MeshType::FaceIterator FaceIterator; - typedef typename MeshType::FaceContainer FaceContainer; - typedef typename vcg::Box3 Box3Type; - typedef typename vcg::face::VFIterator VFLocalIterator; - -class ScaleLaplacianInfo -{ -public: - CoordType PntSum; - ScalarType LenSum; -}; - -// This is precisely what curvature flow does. -// Curvature flow smoothes the surface by moving along the surface -// normal n with a speed equal to the mean curvature -void VertexCoordLaplacianCurvatureFlow(MeshType &m, int step, ScalarType delta) -{ - -} - -// Another Laplacian smoothing variant, -// here we sum the baricenter of the faces incidents on each vertex weighting them with the angle - -static void VertexCoordLaplacianAngleWeighted(MeshType &m, int step, ScalarType delta) -{ - ScaleLaplacianInfo lpz; - lpz.PntSum=CoordType(0,0,0); - lpz.LenSum=0; - SimpleTempData TD(m.vert,lpz); - FaceIterator fi; - for(int i=0;iP() + (*fi).V(1)->P() + (*fi).V(2)->P())/3.0; - CoordType e0=((*fi).V(0)->P() - (*fi).V(1)->P()).Normalize(); - CoordType e1=((*fi).V(1)->P() - (*fi).V(2)->P()).Normalize(); - CoordType e2=((*fi).V(2)->P() - (*fi).V(0)->P()).Normalize(); - - a[0]=AngleN(-e0,e2); - a[1]=AngleN(-e1,e0); - a[2]=AngleN(-e2,e1); - //assert(fabs(M_PI -a[0] -a[1] -a[2])<0.0000001); - - for(int j=0;j<3;++j){ - CoordType dir= (mp-(*fi).V(j)->P()).Normalize(); - TD[(*fi).V(j)].PntSum+=dir*a[j]; - TD[(*fi).V(j)].LenSum+=a[j]; // well, it should be named angleSum - } - } - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - if(!(*vi).IsD() && TD[*vi].LenSum>0 ) - (*vi).P() = (*vi).P() + (TD[*vi].PntSum/TD[*vi].LenSum ) * delta; - - } -}; - -// Scale dependent laplacian smoothing [Fujiwara 95] -// as described in -// Implicit Fairing of Irregular Meshes using Diffusion and Curvature Flow -// Mathieu Desbrun, Mark Meyer, Peter Schroeder, Alan H. Barr -// SIGGRAPH 99 -// REQUIREMENTS: Border Flags. -// -// Note the delta parameter is in a absolute unit -// to get stability it should be a small percentage of the shortest edge. - -static void VertexCoordScaleDependentLaplacian_Fujiwara(MeshType &m, int step, ScalarType delta) -{ - SimpleTempData TD(m.vert); - ScaleLaplacianInfo lpz; - lpz.PntSum=CoordType(0,0,0); - lpz.LenSum=0; - FaceIterator fi; - for(int i=0;iP() -(*fi).V(j)->P(); - ScalarType len=Norm(edge); - edge/=len; - TD[(*fi).V(j)].PntSum+=edge; - TD[(*fi).V1(j)].PntSum-=edge; - TD[(*fi).V(j)].LenSum+=len; - TD[(*fi).V1(j)].LenSum+=len; - } - - for(fi=m.face.begin();fi!=m.face.end();++fi)if(!(*fi).IsD()) - for(int j=0;j<3;++j) - // se l'edge j e' di bordo si riazzera tutto e si riparte - if((*fi).IsB(j)) { - TD[(*fi).V(j)].PntSum=CoordType(0,0,0); - TD[(*fi).V1(j)].PntSum=CoordType(0,0,0); - TD[(*fi).V(j)].LenSum=0; - TD[(*fi).V1(j)].LenSum=0; - } - - - for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) - for(int j=0;j<3;++j) - if((*fi).IsB(j)) - { - CoordType edge= (*fi).V1(j)->P() -(*fi).V(j)->P(); - ScalarType len=Norm(edge); - edge/=len; - TD[(*fi).V(j)].PntSum+=edge; - TD[(*fi).V1(j)].PntSum-=edge; - TD[(*fi).V(j)].LenSum+=len; - TD[(*fi).V1(j)].LenSum+=len; - } - // The fundamental part: - // We move the new point of a quantity - // - // L(M) = 1/Sum(edgelen) * Sum(Normalized edges) - // - - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - if(!(*vi).IsD() && TD[*vi].LenSum>0 ) - (*vi).P() = (*vi).P() + (TD[*vi].PntSum/TD[*vi].LenSum)*delta; - } -}; - - -class LaplacianInfo -{ -public: - LaplacianInfo(const CoordType &_p, const int _n):sum(_p),cnt(_n) {} - LaplacianInfo() {} - CoordType sum; - ScalarType cnt; -}; - -// Classical Laplacian Smoothing. Each vertex can be moved onto the average of the adjacent vertices. -// Can smooth only the selected vertices and weight the smoothing according to the quality -// In the latter case 0 means that the vertex is not moved and 1 means that the vertex is moved onto the computed position. -// -// From the Taubin definition "A signal proc approach to fair surface design" -// We define the discrete Laplacian of a discrete surface signal by weighted averages over the neighborhoods -// \delta xi = \Sum wij (xj - xi) ; -// where xj are the adjacent vertices of xi and wij is usually 1/n_adj -// -// This function simply accumulate over a TempData all the positions of the ajacent vertices -// -static void AccumulateLaplacianInfo(MeshType &m, SimpleTempData &TD) -{ - FaceIterator fi; - for(fi=m.face.begin();fi!=m.face.end();++fi) - { - if(!(*fi).IsD()) - for(int j=0;j<3;++j) - if(!(*fi).IsB(j)) - { - TD[(*fi).V(j)].sum+=(*fi).V1(j)->P(); - TD[(*fi).V1(j)].sum+=(*fi).V(j)->P(); - ++TD[(*fi).V(j)].cnt; - ++TD[(*fi).V1(j)].cnt; - } - } - // si azzaera i dati per i vertici di bordo - for(fi=m.face.begin();fi!=m.face.end();++fi) - { - if(!(*fi).IsD()) - for(int j=0;j<3;++j) - if((*fi).IsB(j)) - { - TD[(*fi).V0(j)].sum=(*fi).P0(j); - TD[(*fi).V1(j)].sum=(*fi).P1(j); - TD[(*fi).V0(j)].cnt=1; - TD[(*fi).V1(j)].cnt=1; - } - } - - // se l'edge j e' di bordo si deve mediare solo con gli adiacenti - for(fi=m.face.begin();fi!=m.face.end();++fi) - { - if(!(*fi).IsD()) - for(int j=0;j<3;++j) - if((*fi).IsB(j)) - { - TD[(*fi).V(j)].sum+=(*fi).V1(j)->P(); - TD[(*fi).V1(j)].sum+=(*fi).V(j)->P(); - ++TD[(*fi).V(j)].cnt; - ++TD[(*fi).V1(j)].cnt; - } - } -} - -static void VertexCoordLaplacian(MeshType &m, int step, bool SmoothSelected=false, vcg::CallBackPos * cb=0) -{ - VertexIterator vi; - LaplacianInfo lpz(CoordType(0,0,0),0); - SimpleTempData TD(m.vert,lpz); - for(int i=0;i0 ) - { - if(!SmoothSelected || (*vi).IsS()) - (*vi).P() = ( (*vi).P() + TD[*vi].sum)/(TD[*vi].cnt+1); - } - } -} - -// Same of above but moves only the vertices that do not change FaceOrientation more that the given threshold -static void VertexCoordPlanarLaplacian(MeshType &m, int step, float AngleThrRad = math::ToRad(1.0), bool SmoothSelected=false, vcg::CallBackPos * cb=0) -{ - VertexIterator vi; - FaceIterator fi; - LaplacianInfo lpz(CoordType(0,0,0),0); - SimpleTempData TD(m.vert,lpz); - for(int i=0;i0 ) - { - if(!SmoothSelected || (*vi).IsS()) - TD[*vi].sum = ( (*vi).P() + TD[*vi].sum)/(TD[*vi].cnt+1); - } - - for(fi=m.face.begin();fi!=m.face.end();++fi){ - if(!(*fi).IsD()){ - for (int j = 0; j < 3; ++j) { - if(Angle( NormalizedNormal(TD[(*fi).V0(j)].sum, (*fi).P1(j), (*fi).P2(j) ), - NormalizedNormal( (*fi).P0(j) , (*fi).P1(j), (*fi).P2(j) ) ) > AngleThrRad ) - TD[(*fi).V0(j)].sum = (*fi).P0(j); - } - } - } - for(fi=m.face.begin();fi!=m.face.end();++fi){ - if(!(*fi).IsD()){ - for (int j = 0; j < 3; ++j) { - if(Angle( NormalizedNormal(TD[(*fi).V0(j)].sum, TD[(*fi).V1(j)].sum, (*fi).P2(j) ), - NormalizedNormal( (*fi).P0(j) , (*fi).P1(j), (*fi).P2(j) ) ) > AngleThrRad ) - { - TD[(*fi).V0(j)].sum = (*fi).P0(j); - TD[(*fi).V1(j)].sum = (*fi).P1(j); - } - } - } - } - - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - if(!(*vi).IsD() && TD[*vi].cnt>0 ) - (*vi).P()= TD[*vi].sum; - - - - }// end step - - -} - -static void VertexCoordLaplacianBlend(MeshType &m, int step, float alpha, bool SmoothSelected=false) -{ - VertexIterator vi; - LaplacianInfo lpz(CoordType(0,0,0),0); - assert (alpha<= 1.0); - SimpleTempData TD(m.vert); - - for(int i=0;i0 ) - { - if(!SmoothSelected || (*vi).IsS()) - { - CoordType Delta = TD[*vi].sum/TD[*vi].cnt - (*vi).P(); - (*vi).P() = (*vi).P() + Delta*alpha; - } - } - } -} - -/* a couple of notes about the lambda mu values -We assume that 0 < lambda , and mu is a negative scale factor such that mu < - lambda. -Holds mu+lambda < 0 (e.g in absolute value mu is greater) - -let kpb be the pass-band frequency, taubin says that: - kpb = 1/lambda + 1/mu >0 - -Values of kpb from 0.01 to 0.1 produce good results according to the original paper. - -kpb * mu - mu/lambda = 1 -mu = 1/(kpb-1/lambda ) - -So if -* lambda == 0.5, kpb==0.1 -> mu = 1/(0.1 - 2) = -0.526 -* lambda == 0.5, kpb==0.01 -> mu = 1/(0.01 - 2) = -0.502 -*/ - - -static void VertexCoordTaubin(MeshType &m, int step, float lambda, float mu, bool SmoothSelected=false, vcg::CallBackPos * cb=0) -{ - LaplacianInfo lpz(CoordType(0,0,0),0); - SimpleTempData TD(m.vert,lpz); - VertexIterator vi; - for(int i=0;i0 ) - { - if(!SmoothSelected || (*vi).IsS()) - { - CoordType Delta = TD[*vi].sum/TD[*vi].cnt - (*vi).P(); - (*vi).P() = (*vi).P() + Delta*lambda ; - } - } - TD.Init(lpz); - AccumulateLaplacianInfo(m,TD); - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - if(!(*vi).IsD() && TD[*vi].cnt>0 ) - { - if(!SmoothSelected || (*vi).IsS()) - { - CoordType Delta = TD[*vi].sum/TD[*vi].cnt - (*vi).P(); - (*vi).P() = (*vi).P() + Delta*mu ; - } - } - } // end for step -} - - -static void VertexCoordLaplacianQuality(MeshType &m, int step, bool SmoothSelected=false) -{ - LaplacianInfo lpz; - lpz.sum=CoordType(0,0,0); - lpz.cnt=1; - SimpleTempData TD(m.vert,lpz); - for(int i=0;i0 ) - if(!SmoothSelected || (*vi).IsS()) - { - float q=(*vi).Q(); - (*vi).P()=(*vi).P()*q + (TD[*vi].sum/TD[*vi].cnt)*(1.0-q); - } - } // end for -}; - -/* - Improved Laplacian Smoothing of Noisy Surface Meshes - J. Vollmer, R. Mencl, and H. M�ller - EUROGRAPHICS Volume 18 (1999), Number 3 -*/ - -class HCSmoothInfo -{ -public: - CoordType dif; - CoordType sum; - int cnt; -}; - -static void VertexCoordLaplacianHC(MeshType &m, int step, bool SmoothSelected=false ) -{ - ScalarType beta=0.5; - HCSmoothInfo lpz; - lpz.sum=CoordType(0,0,0); - lpz.dif=CoordType(0,0,0); - lpz.cnt=0; - for(int i=0;i TD(m.vert,lpz); - // First Loop compute the laplacian - FaceIterator fi; - for(fi=m.face.begin();fi!=m.face.end();++fi)if(!(*fi).IsD()) - { - for(int j=0;j<3;++j) - { - TD[(*fi).V(j)].sum+=(*fi).V1(j)->P(); - TD[(*fi).V1(j)].sum+=(*fi).V(j)->P(); - ++TD[(*fi).V(j)].cnt; - ++TD[(*fi).V1(j)].cnt; - // se l'edge j e' di bordo si deve sommare due volte - if((*fi).IsB(j)) - { - TD[(*fi).V(j)].sum+=(*fi).V1(j)->P(); - TD[(*fi).V1(j)].sum+=(*fi).V(j)->P(); - ++TD[(*fi).V(j)].cnt; - ++TD[(*fi).V1(j)].cnt; - } - } - } - VertexIterator vi; - for(vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD()) - TD[*vi].sum/=(float)TD[*vi].cnt; - - // Second Loop compute average difference - for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) - { - for(int j=0;j<3;++j) - { - TD[(*fi).V(j)].dif +=TD[(*fi).V1(j)].sum-(*fi).V1(j)->P(); - TD[(*fi).V1(j)].dif+=TD[(*fi).V(j)].sum-(*fi).V(j)->P(); - // se l'edge j e' di bordo si deve sommare due volte - if((*fi).IsB(j)) - { - TD[(*fi).V(j)].dif +=TD[(*fi).V1(j)].sum-(*fi).V1(j)->P(); - TD[(*fi).V1(j)].dif+=TD[(*fi).V(j)].sum-(*fi).V(j)->P(); - } - } - } - - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - { - TD[*vi].dif/=(float)TD[*vi].cnt; - if(!SmoothSelected || (*vi).IsS()) - (*vi).P()= TD[*vi].sum - (TD[*vi].sum - (*vi).P())*beta + (TD[*vi].dif)*(1.f-beta); - } - } // end for step -}; - -// Laplacian smooth of the quality. - - -class ColorSmoothInfo -{ -public: - unsigned int r; - unsigned int g; - unsigned int b; - unsigned int a; - int cnt; -}; - -static void VertexColorLaplacian(MeshType &m, int step, bool SmoothSelected=false, vcg::CallBackPos * cb=0) -{ - ColorSmoothInfo csi; - csi.r=0; csi.g=0; csi.b=0; csi.cnt=0; - SimpleTempData TD(m.vert,csi); - - for(int i=0;iC()[0]; - TD[(*fi).V(j)].g+=(*fi).V1(j)->C()[1]; - TD[(*fi).V(j)].b+=(*fi).V1(j)->C()[2]; - TD[(*fi).V(j)].a+=(*fi).V1(j)->C()[3]; - - TD[(*fi).V1(j)].r+=(*fi).V(j)->C()[0]; - TD[(*fi).V1(j)].g+=(*fi).V(j)->C()[1]; - TD[(*fi).V1(j)].b+=(*fi).V(j)->C()[2]; - TD[(*fi).V1(j)].a+=(*fi).V(j)->C()[3]; - - ++TD[(*fi).V(j)].cnt; - ++TD[(*fi).V1(j)].cnt; - } - - // si azzaera i dati per i vertici di bordo - for(fi=m.face.begin();fi!=m.face.end();++fi) - if(!(*fi).IsD()) - for(int j=0;j<3;++j) - if((*fi).IsB(j)) - { - TD[(*fi).V(j)]=csi; - TD[(*fi).V1(j)]=csi; - } - - // se l'edge j e' di bordo si deve mediare solo con gli adiacenti - for(fi=m.face.begin();fi!=m.face.end();++fi) - if(!(*fi).IsD()) - for(int j=0;j<3;++j) - if((*fi).IsB(j)) - { - TD[(*fi).V(j)].r+=(*fi).V1(j)->C()[0]; - TD[(*fi).V(j)].g+=(*fi).V1(j)->C()[1]; - TD[(*fi).V(j)].b+=(*fi).V1(j)->C()[2]; - TD[(*fi).V(j)].a+=(*fi).V1(j)->C()[3]; - - TD[(*fi).V1(j)].r+=(*fi).V(j)->C()[0]; - TD[(*fi).V1(j)].g+=(*fi).V(j)->C()[1]; - TD[(*fi).V1(j)].b+=(*fi).V(j)->C()[2]; - TD[(*fi).V1(j)].a+=(*fi).V(j)->C()[3]; - - ++TD[(*fi).V(j)].cnt; - ++TD[(*fi).V1(j)].cnt; - } - - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - if(!(*vi).IsD() && TD[*vi].cnt>0 ) - if(!SmoothSelected || (*vi).IsS()) - { - (*vi).C()[0] = (unsigned int) ceil((double) (TD[*vi].r / TD[*vi].cnt)); - (*vi).C()[1] = (unsigned int) ceil((double) (TD[*vi].g / TD[*vi].cnt)); - (*vi).C()[2] = (unsigned int) ceil((double) (TD[*vi].b / TD[*vi].cnt)); - (*vi).C()[3] = (unsigned int) ceil((double) (TD[*vi].a / TD[*vi].cnt)); - } - } // end for step -}; - -static void FaceColorLaplacian(MeshType &m, int step, bool SmoothSelected=false, vcg::CallBackPos * cb=0) -{ - ColorSmoothInfo csi; - csi.r=0; csi.g=0; csi.b=0; csi.cnt=0; - SimpleTempData TD(m.face,csi); - - for(int i=0;iC()[0]; - TD[*fi].g+=(*fi).FFp(j)->C()[1]; - TD[*fi].b+=(*fi).FFp(j)->C()[2]; - TD[*fi].a+=(*fi).FFp(j)->C()[3]; - ++TD[*fi].cnt; - } - } - for(fi=m.face.begin();fi!=m.face.end();++fi) - if(!(*fi).IsD() && TD[*fi].cnt>0 ) - if(!SmoothSelected || (*fi).IsS()) - { - (*fi).C()[0] = (unsigned int) ceil((float) (TD[*fi].r / TD[*fi].cnt)); - (*fi).C()[1] = (unsigned int) ceil((float) (TD[*fi].g / TD[*fi].cnt)); - (*fi).C()[2] = (unsigned int) ceil((float) (TD[*fi].b / TD[*fi].cnt)); - (*fi).C()[3] = (unsigned int) ceil((float) (TD[*fi].a / TD[*fi].cnt)); - } - } // end for step -}; - -// Laplacian smooth of the quality. - -class QualitySmoothInfo -{ -public: - ScalarType sum; - int cnt; -}; - - -static void VertexQualityLaplacian(MeshType &m, int step=1, bool SmoothSelected=false) -{ - QualitySmoothInfo lpz; - lpz.sum=0; - lpz.cnt=0; - SimpleTempData TD(m.vert,lpz); - //TD.Start(lpz); - for(int i=0;iQ(); - TD[(*fi).V1(j)].sum+=(*fi).V(j)->Q(); - ++TD[(*fi).V(j)].cnt; - ++TD[(*fi).V1(j)].cnt; - } - - // si azzaera i dati per i vertici di bordo - for(fi=m.face.begin();fi!=m.face.end();++fi) - if(!(*fi).IsD()) - for(int j=0;j<3;++j) - if((*fi).IsB(j)) - { - TD[(*fi).V(j)]=lpz; - TD[(*fi).V1(j)]=lpz; - } - - // se l'edge j e' di bordo si deve mediare solo con gli adiacenti - for(fi=m.face.begin();fi!=m.face.end();++fi) - if(!(*fi).IsD()) - for(int j=0;j<3;++j) - if((*fi).IsB(j)) - { - TD[(*fi).V(j)].sum+=(*fi).V1(j)->Q(); - TD[(*fi).V1(j)].sum+=(*fi).V(j)->Q(); - ++TD[(*fi).V(j)].cnt; - ++TD[(*fi).V1(j)].cnt; - } - - //VertexIterator vi; - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - if(!(*vi).IsD() && TD[*vi].cnt>0 ) - if(!SmoothSelected || (*vi).IsS()) - (*vi).Q()=TD[*vi].sum/TD[*vi].cnt; - } - - //TD.Stop(); -}; - -static void VertexNormalLaplacian(MeshType &m, int step,bool SmoothSelected=false) -{ - LaplacianInfo lpz; - lpz.sum=CoordType(0,0,0); - lpz.cnt=0; - SimpleTempData TD(m.vert,lpz); - for(int i=0;iN(); - TD[(*fi).V1(j)].sum+=(*fi).V(j)->N(); - ++TD[(*fi).V(j)].cnt; - ++TD[(*fi).V1(j)].cnt; - } - - // si azzaera i dati per i vertici di bordo - for(fi=m.face.begin();fi!=m.face.end();++fi) - if(!(*fi).IsD()) - for(int j=0;j<3;++j) - if((*fi).IsB(j)) - { - TD[(*fi).V(j)]=lpz; - TD[(*fi).V1(j)]=lpz; - } - - // se l'edge j e' di bordo si deve mediare solo con gli adiacenti - for(fi=m.face.begin();fi!=m.face.end();++fi) - if(!(*fi).IsD()) - for(int j=0;j<3;++j) - if((*fi).IsB(j)) - { - TD[(*fi).V(j)].sum+=(*fi).V1(j)->N(); - TD[(*fi).V1(j)].sum+=(*fi).V(j)->N(); - ++TD[(*fi).V(j)].cnt; - ++TD[(*fi).V1(j)].cnt; - } - - //VertexIterator vi; - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - if(!(*vi).IsD() && TD[*vi].cnt>0 ) - if(!SmoothSelected || (*vi).IsS()) - (*vi).N()=TD[*vi].sum/TD[*vi].cnt; - } - -}; - -// Smooth solo lungo la direzione di vista - // alpha e' compreso fra 0(no smoot) e 1 (tutto smoot) - // Nota che se smootare il bordo puo far fare bandierine. -static void VertexCoordViewDepth(MeshType &m, - const CoordType & viewpoint, - const ScalarType alpha, - int step, bool SmoothBorder=false ) -{ - LaplacianInfo lpz; - lpz.sum=CoordType(0,0,0); - lpz.cnt=0; - SimpleTempData TD(m.vert,lpz); - for(int i=0;icP(); - TD[(*fi).V1(j)].sum+=(*fi).V(j)->cP(); - ++TD[(*fi).V(j)].cnt; - ++TD[(*fi).V1(j)].cnt; - } - - // si azzaera i dati per i vertici di bordo - for(fi=m.face.begin();fi!=m.face.end();++fi) - if(!(*fi).IsD()) - for(int j=0;j<3;++j) - if((*fi).IsB(j)) - { - TD[(*fi).V(j)]=lpz; - TD[(*fi).V1(j)]=lpz; - } - - // se l'edge j e' di bordo si deve mediare solo con gli adiacenti - if(SmoothBorder) - for(fi=m.face.begin();fi!=m.face.end();++fi) - if(!(*fi).IsD()) - for(int j=0;j<3;++j) - if((*fi).IsB(j)) - { - TD[(*fi).V(j)].sum+=(*fi).V1(j)->cP(); - TD[(*fi).V1(j)].sum+=(*fi).V(j)->cP(); - ++TD[(*fi).V(j)].cnt; - ++TD[(*fi).V1(j)].cnt; - } - - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - if(!(*vi).IsD() && TD[*vi].cnt>0 ) - { - CoordType np = TD[*vi].sum/TD[*vi].cnt; - CoordType d = (*vi).cP() - viewpoint; d.Normalize(); - ScalarType s = d .dot ( np - (*vi).cP() ); - (*vi).P() += d * (s*alpha); - } - } -} - - - -/****************************************************************************************************************/ -/****************************************************************************************************************/ -// Paso Double Smoothing -// The proposed -// approach is a two step method where in the first step the face normals -// are adjusted and then, in a second phase, the vertex positions are updated. -/****************************************************************************************************************/ -/****************************************************************************************************************/ -// Classi di info - -class PDVertInfo -{ -public: - CoordType np; -}; - - -class PDFaceInfo -{ -public: - CoordType m; -}; -/***************************************************************************/ -// Paso Doble Step 1 compute the smoothed normals -/***************************************************************************/ -// Requirements: -// VF Topology -// Normalized Face Normals -// -// This is the Normal Smoothing approach of Shen and Berner -// Fuzzy Vector Median-Based Surface Smoothing TVCG 2004 - - -void FaceNormalFuzzyVectorSB(MeshType &m, - SimpleTempData &TD, - ScalarType sigma) -{ - int i; - - FaceIterator fi; - - for(fi=m.face.begin();fi!=m.face.end();++fi) - { - CoordType bc=(*fi).Barycenter(); - // 1) Clear all the visited flag of faces that are vertex-adjacent to fi - for(i=0;i<3;++i) - { - vcg::face::VFIterator ep(&*fi,i); - while (!ep.End()) - { - ep.f->ClearV(); - ++ep; - } - } - - // 1) Effectively average the normals weighting them with - (*fi).SetV(); - CoordType mm=CoordType(0,0,0); - for(i=0;i<3;++i) - { - vcg::face::VFIterator ep(&*fi,i); - while (!ep.End()) - { - if(! (*ep.f).IsV() ) - { - if(sigma>0) - { - ScalarType dd=SquaredDistance(ep.f->Barycenter(),bc); - ScalarType ang=AngleN(ep.f->N(),(*fi).N()); - mm+=ep.f->N()*exp((-sigma)*ang*ang/dd); - } - else mm+=ep.f->N(); - (*ep.f).SetV(); - } - ++ep; - } - } - mm.Normalize(); - TD[*fi].m=mm; - } -} - -// Replace the normal of the face with the average of normals of the vertex adijacent faces. -// Normals are weighted with face area. -// It assumes that: -// Normals are normalized: -// VF adjacency is present. - -static void FaceNormalLaplacianVF(MeshType &m) -{ - SimpleTempData TDF(m.face); - - PDFaceInfo lpzf; - lpzf.m=CoordType(0,0,0); - - assert(tri::HasPerVertexVFAdjacency(m) && tri::HasPerFaceVFAdjacency(m) ); - TDF.Start(lpzf); - int i; - - FaceIterator fi; - - tri::UpdateNormals::AreaNormalizeFace(m); - - for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) - { - CoordType bc=Barycenter(*fi); - // 1) Clear all the visited flag of faces that are vertex-adjacent to fi - for(i=0;i<3;++i) - { - VFLocalIterator ep(&*fi,i); - for (;!ep.End();++ep) - ep.f->ClearV(); - } - - // 2) Effectively average the normals - CoordType normalSum=(*fi).N(); - - for(i=0;i<3;++i) - { - VFLocalIterator ep(&*fi,i); - for (;!ep.End();++ep) - { - if(! (*ep.f).IsV() ) - { - normalSum += ep.f->N(); - (*ep.f).SetV(); - } - } - } - normalSum.Normalize(); - TDF[*fi].m=normalSum; - } - for(fi=m.face.begin();fi!=m.face.end();++fi) - (*fi).N()=TDF[*fi].m; - - tri::UpdateNormals::NormalizeFace(m); - - TDF.Stop(); -} - -// Replace the normal of the face with the average of normals of the face adijacent faces. -// Normals are weighted with face area. -// It assumes that: -// Normals are normalized: -// FF adjacency is present. - - -static void FaceNormalLaplacianFF(MeshType &m, int step=1, bool SmoothSelected=false ) -{ - PDFaceInfo lpzf; - lpzf.m=CoordType(0,0,0); - SimpleTempData TDF(m.face,lpzf); - assert(tri::HasFFAdjacency(m)); - - FaceIterator fi; - tri::UpdateNormals::AreaNormalizeFace(m); - for(int i=0;iN(); - - TDF[*fi].m=normalSum; - } - for(fi=m.face.begin();fi!=m.face.end();++fi) - if(!SmoothSelected || (*fi).IsS()) - (*fi).N()=TDF[*fi].m; - - tri::UpdateNormals::NormalizeFace(m); - } -} - - -/***************************************************************************/ -// Paso Doble Step 1 compute the smoothed normals -/***************************************************************************/ -// Requirements: -// VF Topology -// Normalized Face Normals -// -// This is the Normal Smoothing approach bsased on a angle thresholded weighting -// sigma is in the 0 .. 1 range, it represent the cosine of a threshold angle. -// sigma == 0 All the normals are averaged -// sigma == 1 Nothing is averaged. -// Only within the specified range are averaged toghether. The averagin is weighted with the - - -static void FaceNormalAngleThreshold(MeshType &m, - SimpleTempData &TD, - ScalarType sigma) -{ - int i; - - - FaceIterator fi; - - for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) - { - CoordType bc=Barycenter(*fi); - // 1) Clear all the visited flag of faces that are vertex-adjacent to fi - for(i=0;i<3;++i) - { - VFLocalIterator ep(&*fi,i); - for (;!ep.End();++ep) - ep.f->ClearV(); - } - - // 1) Effectively average the normals weighting them with the squared difference of the angle similarity - // sigma is the cosine of a threshold angle. sigma \in 0..1 - // sigma == 0 All the normals are averaged - // sigma == 1 Nothing is averaged. - // The averaging is weighted with the difference between normals. more similar the normal more important they are. - - CoordType normalSum=CoordType(0,0,0); - for(i=0;i<3;++i) - { - VFLocalIterator ep(&*fi,i); - for (;!ep.End();++ep) - { - if(! (*ep.f).IsV() ) - { - ScalarType cosang=ep.f->N().dot((*fi).N()); - // Note that if two faces form an angle larger than 90 deg, their contribution should be very very small. - // Without this clamping - cosang = math::Clamp(cosang,0.0001f,1.f); - if(cosang >= sigma) - { - ScalarType w = cosang-sigma; - normalSum += ep.f->N()*(w*w); // similar normals have a cosang very close to 1 so cosang - sigma is maximized - } - (*ep.f).SetV(); - } - } - } - normalSum.Normalize(); - TD[*fi].m=normalSum; - } - - for(fi=m.face.begin();fi!=m.face.end();++fi) - (*fi).N()=TD[*fi].m; -} - -/****************************************************************************************************************/ -// Restituisce il gradiente dell'area del triangolo nel punto p. -// Nota che dovrebbe essere sempre un vettore che giace nel piano del triangolo e perpendicolare al lato opposto al vertice p. -// Ottimizzato con Maple e poi pesantemente a mano. - -CoordType TriAreaGradient(CoordType &p,CoordType &p0,CoordType &p1) -{ - CoordType dd = p1-p0; - CoordType d0 = p-p0; - CoordType d1 = p-p1; - CoordType grad; - - ScalarType t16 = d0[1]* d1[2] - d0[2]* d1[1]; - ScalarType t5 = -d0[2]* d1[0] + d0[0]* d1[2]; - ScalarType t4 = -d0[0]* d1[1] + d0[1]* d1[0]; - - ScalarType delta= sqrtf(t4*t4 + t5*t5 +t16*t16); - - grad[0]= (t5 * (-dd[2]) + t4 * ( dd[1]))/delta; - grad[1]= (t16 * (-dd[2]) + t4 * (-dd[0]))/delta; - grad[2]= (t16 * ( dd[1]) + t5 * ( dd[0]))/delta; - - return grad; -} - -template -CoordType CrossProdGradient(CoordType &p, CoordType &p0, CoordType &p1, CoordType &m) -{ - CoordType grad; - CoordType p00=p0-p; - CoordType p01=p1-p; - grad[0] = (-p00[2] + p01[2])*m[1] + (-p01[1] + p00[1])*m[2]; - grad[1] = (-p01[2] + p00[2])*m[0] + (-p00[0] + p01[0])*m[2]; - grad[2] = (-p00[1] + p01[1])*m[0] + (-p01[0] + p00[0])*m[1]; - - return grad; -} - -/* -Deve Calcolare il gradiente di -E(p) = A(p,p0,p1) (n - m)^2 = -A(...) (2-2nm) = -(p0-p)^(p1-p) -2A - 2A * ------------- m = -2A - -2A - 2 (p0-p)^(p1-p) * m -*/ - -CoordType FaceErrorGrad(CoordType &p,CoordType &p0,CoordType &p1, CoordType &m) -{ - return TriAreaGradient(p,p0,p1) *2.0f - - CrossProdGradient(p,p0,p1,m) *2.0f ; -} -/***************************************************************************/ -// Paso Doble Step 2 Fitta la mesh a un dato insieme di normali -/***************************************************************************/ - - -void FitMesh(MeshType &m, - SimpleTempData &TDV, - SimpleTempData &TDF, - float lambda) -{ - //vcg::face::Pos ep; - vcg::face::VFIterator ep; - VertexIterator vi; - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - { - CoordType ErrGrad=CoordType(0,0,0); - - ep.f=(*vi).VFp(); - ep.z=(*vi).VFi(); - while (!ep.End()) - { - ErrGrad+=FaceErrorGrad(ep.f->V(ep.z)->P(),ep.f->V1(ep.z)->P(),ep.f->V2(ep.z)->P(),TDF[ep.f].m); - ++ep; - } - TDV[*vi].np=(*vi).P()-ErrGrad*(ScalarType)lambda; - } - - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - (*vi).P()=TDV[*vi].np; - -} -/****************************************************************************************************************/ - - - -static void FastFitMesh(MeshType &m, - SimpleTempData &TDV, - //SimpleTempData &TDF, - bool OnlySelected=false) -{ - //vcg::face::Pos ep; - vcg::face::VFIterator ep; - VertexIterator vi; - - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - { - CoordType Sum(0,0,0); - ScalarType cnt=0; - VFLocalIterator ep(&*vi); - for (;!ep.End();++ep) - { - CoordType bc=Barycenter(*ep.F()); - Sum += ep.F()->N()*(ep.F()->N().dot(bc - (*vi).P())); - ++cnt; - } - TDV[*vi].np=(*vi).P()+ Sum*(1.0/cnt); - } - - if(OnlySelected) - { - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - if((*vi).IsS()) (*vi).P()=TDV[*vi].np; - } - else - { - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - (*vi).P()=TDV[*vi].np; - } -} - - - -static void VertexCoordPasoDoble(MeshType &m, int step, typename MeshType::ScalarType Sigma=0, int FitStep=10, typename MeshType::ScalarType FitLambda=0.05) -{ - SimpleTempData< typename MeshType::VertContainer, PDVertInfo> TDV(m.vert); - SimpleTempData< typename MeshType::FaceContainer, PDFaceInfo> TDF(m.face); - PDVertInfo lpzv; - lpzv.np=CoordType(0,0,0); - PDFaceInfo lpzf; - lpzf.m=CoordType(0,0,0); - - assert(m.HasVFTopology()); - m.HasVFTopology(); - TDV.Start(lpzv); - TDF.Start(lpzf); - for(int j=0;j::PerFace(m); - FaceNormalAngleThreshold(m,TDF,Sigma); - for(int k=0;k TDV(m.vert,lpzv); - SimpleTempData< typename MeshType::FaceContainer, PDFaceInfo> TDF(m.face,lpzf); - - for(int j=0;j -static void VertexCoordLaplacianReproject(MeshType& m, GRID& grid, MeshTypeTri& gridmesh) -{ - typename MeshType::VertexIterator vi; - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - { - if(! (*vi).IsD()) - VertexCoordLaplacianReproject(m,grid,gridmesh,&*vi); - } -} - - -template -static void VertexCoordLaplacianReproject(MeshType& m, GRID& grid, MeshTypeTri& gridmesh, typename MeshType::VertexType* vp) -{ - assert(MeshType::HEdgeType::HasHVAdjacency()); - - // compute barycenter - typedef std::vector VertexSet; - VertexSet verts; - verts = HalfEdgeTopology::getVertices(vp); - - typename MeshType::CoordType ct(0,0,0); - for(typename VertexSet::iterator it = verts.begin(); it != verts.end(); ++it) - { - ct += (*it)->P(); - } - ct /= verts.size(); - - // move vertex - vp->P() = ct; - - - vector faces2 = HalfEdgeTopology::get_incident_faces(vp); - - // estimate normal - typename MeshType::CoordType avgn(0,0,0); - - for(unsigned int i = 0;i< faces2.size();i++) - if(faces2[i]) - { - vector vertices = HalfEdgeTopology::getVertices(faces2[i]); - - assert(vertices.size() == 4); - - avgn += vcg::Normal(vertices[0]->cP(), vertices[1]->cP(), vertices[2]->cP()); - avgn += vcg::Normal(vertices[2]->cP(), vertices[3]->cP(), vertices[0]->cP()); - - } - avgn.Normalize(); - - // reproject - ScalarType diag = m.bbox.Diag(); - typename MeshType::CoordType raydir = avgn; - Ray3 ray; - - ray.SetOrigin(vp->P()); - ScalarType t; - typename MeshTypeTri::FaceType* f = 0; - typename MeshTypeTri::FaceType* fr = 0; - - vector closests; - vector minDists; - vector faces; - ray.SetDirection(-raydir); - f = vcg::tri::DoRay(gridmesh, grid, ray, diag/4.0, t); - - if (f) - { - closests.push_back(ray.Origin() + ray.Direction()*t); - minDists.push_back(fabs(t)); - faces.push_back(f); - } - ray.SetDirection(raydir); - fr = vcg::tri::DoRay(gridmesh, grid, ray, diag/4.0, t); - if (fr) - { - closests.push_back(ray.Origin() + ray.Direction()*t); - minDists.push_back(fabs(t)); - faces.push_back(fr); - } - - if (fr) if (fr->N()*raydir<0) fr=0; // discard: inverse normal; - typename MeshType::CoordType newPos; - if (minDists.size() == 0) - { - newPos = vp->P(); - f = 0; - } - else - { - int minI = std::min_element(minDists.begin(),minDists.end()) - minDists.begin(); - newPos = closests[minI]; - f = faces[minI]; - } - - if (f) - vp->P() = newPos; -} - -}; //end Smooth class - -} // End namespace tri -} // End namespace vcg - -#endif // VCG_SMOOTH diff --git a/vcg/complex/trimesh/stat.h b/vcg/complex/trimesh/stat.h deleted file mode 100644 index 06b9babe..00000000 --- a/vcg/complex/trimesh/stat.h +++ /dev/null @@ -1,246 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2006 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ -/**************************************************************************** -History - -$Log: not supported by cvs2svn $ -Revision 1.3 2007/01/11 10:12:19 cignoni -Removed useless and conflicting inclusion of face.h - -Revision 1.2 2006/05/25 09:39:09 cignoni -missing std and other gcc detected syntax errors - -Revision 1.1 2006/05/21 06:59:13 cignoni -Initial Commit - -****************************************************************************/ - -#ifndef __VCGLIB_TRIMESH_STAT -#define __VCGLIB_TRIMESH_STAT - -// Standard headers -// VCG headers - -#include -#include -#include -#include -#include -#include -#include - - -namespace vcg { - namespace tri{ -template -class Stat -{ - public: - typedef StatMeshType MeshType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::FacePointer FacePointer; - typedef typename MeshType::FaceIterator FaceIterator; - typedef typename MeshType::FaceContainer FaceContainer; - typedef typename vcg::Box3 Box3Type; - - static std::pair ComputePerVertexQualityMinMax( MeshType & m) // V1.0 - { - std::pair minmax = std::make_pair(std::numeric_limits::max(),-std::numeric_limits::max()); - - VertexIterator vi; - for(vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if(!(*vi).IsD()) - { - if( (*vi).Q() < minmax.first) minmax.first=(*vi).Q(); - if( (*vi).Q() > minmax.second) minmax.second=(*vi).Q(); - } - return minmax; - } - - static std::pair ComputePerFaceQualityMinMax( MeshType & m) // V1.0 - { - std::pair minmax = std::make_pair(std::numeric_limits::max(),-std::numeric_limits::max()); - - FaceIterator fi; - for(fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - { - if( (*fi).Q() < minmax.first) minmax.first =(*fi).Q(); - if( (*fi).Q() > minmax.second) minmax.second=(*fi).Q(); - } - return minmax; - } - - /** - \short compute the barycenter of the surface thin-shell. - E.g. it assume a 'empty' model where all the mass is located on the surface and compute the barycenter of that thinshell. - Works for any triangulated model (no problem with open, nonmanifold selfintersecting models). - Useful for computing the barycenter of 2D planar figures. - */ - static Point3 ComputeShellBarycenter(MeshType & m) - { - Point3 barycenter(0,0,0); - ScalarType areaSum=0; - FaceIterator fi; - for(fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - { - ScalarType area=DoubleArea(*fi); - barycenter += Barycenter(*fi)*area; - areaSum+=area; - } - return barycenter/areaSum; - } - - - static ScalarType ComputeMeshArea(MeshType & m) - { - ScalarType area=0; - - FaceIterator fi; - for(fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - area += DoubleArea(*fi); - - return area/ScalarType(2.0); - } - - static void ComputePerVertexQualityDistribution( MeshType & m, Distribution &h, bool selectionOnly = false) // V1.0 - { - VertexIterator vi; - for(vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if(!(*vi).IsD() && ((!selectionOnly) || (*vi).IsS()) ) - { - assert(!math::IsNAN((*vi).Q()) && "You should never try to compute Histogram with Invalid Floating points numbers (NaN)"); - h.Add((*vi).Q()); - } - } - - static void ComputePerFaceQualityDistribution( MeshType & m, Distribution &h, bool selectionOnly = false) // V1.0 - { - FaceIterator fi; - for(fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD() && ((!selectionOnly) || (*fi).IsS()) ) - { - assert(!math::IsNAN((*fi).Q()) && "You should never try to compute Histogram with Invalid Floating points numbers (NaN)"); - h.Add((*fi).Q()); - } - } - - static void ComputePerFaceQualityHistogram( MeshType & m, Histogramf &h, bool selectionOnly=false,int HistSize=10000 ) - { - std::pair minmax = tri::Stat::ComputePerFaceQualityMinMax(m); - h.Clear(); - h.SetRange( minmax.first,minmax.second, HistSize ); - for(FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD() && ((!selectionOnly) || (*fi).IsS()) ){ - assert(!math::IsNAN((*fi).Q()) && "You should never try to compute Histogram with Invalid Floating points numbers (NaN)"); - h.Add((*fi).Q()); - } - } - - static void ComputePerVertexQualityHistogram( MeshType & m, Histogramf &h, bool selectionOnly = false, int HistSize=10000 ) // V1.0 - { - VertexIterator vi; - std::pair minmax = ComputePerVertexQualityMinMax(m); - - h.Clear(); - h.SetRange( minmax.first,minmax.second, HistSize); - for(vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if(!(*vi).IsD() && ((!selectionOnly) || (*vi).IsS()) ) - { - assert(!math::IsNAN((*vi).Q()) && "You should never try to compute Histogram with Invalid Floating points numbers (NaN)"); - h.Add((*vi).Q()); - } - // Sanity check; If some very wrong value has happened in the Q value, - // the histogram is messed. If a significant percentage (20% )of the values are all in a single bin - // we should try to solve the problem. No easy solution here. - // We choose to compute the get the 1percentile and 99 percentile values as new mixmax ranges - // and just to be sure enlarge the Histogram. - - if(h.MaxCount() > HistSize/5) - { - std::vector QV; - QV.reserve(m.vn); - for(vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if(!(*vi).IsD()) QV.push_back((*vi).Q()); - - std::nth_element(QV.begin(),QV.begin()+m.vn/100,QV.end()); - float newmin=*(QV.begin()+m.vn/100); - std::nth_element(QV.begin(),QV.begin()+m.vn-m.vn/100,QV.end()); - float newmax=*(QV.begin()+m.vn-m.vn/100); - - h.Clear(); - h.SetRange(newmin, newmax, HistSize*50); - for(vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if(!(*vi).IsD() && ((!selectionOnly) || (*vi).IsS()) ) - h.Add((*vi).Q()); - } - } - - static int ComputeEdgeHistogram( MeshType & m, Histogramf &h) // V1.0 - { - ScalarType Diag = m.bbox.Diag(); - h.Clear(); - h.SetRange( 0, Diag, 10000); - FaceIterator fi;VertexIterator vi; - for(vi = m.vert.begin(); vi != m.vert.end(); ++vi) (*vi).ClearV(); - for(fi = m.face.begin(); fi != m.face.end(); ++fi) - { - if(!(*fi).IsD()) - { - if( !(*fi).V(0)->IsV() && !(*fi).V(1)->IsV() ) - { - h.Add(Distance((*fi).V(0)->P(),(*fi).V(1)->P())); - (*fi).V(0)->SetV(); - (*fi).V(1)->SetV(); - } - if( !(*fi).V(1)->IsV() && !(*fi).V(2)->IsV()) - { - h.Add(Distance((*fi).V(1)->P(),(*fi).V(2)->P())); - (*fi).V(2)->SetV(); - (*fi).V(1)->SetV(); - } - if( !(*fi).V(2)->IsV() && !(*fi).V(0)->IsV()) - { - h.Add(Distance((*fi).V(2)->P(),(*fi).V(0)->P())); - (*fi).V(0)->SetV(); - (*fi).V(2)->SetV(); - } - } - } - - for(vi = m.vert.begin(); vi != m.vert.end(); ++vi)(*vi).ClearV(); - return 0; - } -}; // end class - - } //End Namespace tri -} // End Namespace vcg - -#endif - diff --git a/vcg/complex/trimesh/subset.h b/vcg/complex/trimesh/subset.h deleted file mode 100644 index e43aa0a3..00000000 --- a/vcg/complex/trimesh/subset.h +++ /dev/null @@ -1,171 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ -/**************************************************************************** - History - -$Log: not supported by cvs2svn $ -Revision 1.12 2007/05/31 09:39:55 cignoni -Small gcc compiling issues - -Revision 1.11 2006/07/06 12:30:32 ganovelli -misleading comment removed - -Revision 1.10 2005/12/14 17:14:13 pietroni -added assert on deleted flag condition - -Revision 1.9 2005/02/08 14:38:05 turini -Warnings Correction - -Revision 1.8 2004/05/17 08:26:28 turini -Changed : Parameters Order As In vcg::tetra::SubSet. - -Revision 1.7 2004/05/17 07:58:16 turini -Minor Changes To Compile Even Without using namespace std. - -Revision 1.6 2004/05/14 11:43:17 turini -Changed mesh ClearFlag call. - -Revision 1.5 2004/05/13 09:59:20 turini -Added typedef typename in InsertedV - -Revision 1.4 2004/05/07 10:06:46 turini -include Plane3 removed. - -Revision 1.3 2004/05/07 09:35:09 turini -Added History Info - -****************************************************************************/ - - -#ifndef __VCGLIB_TRISUBSET -#define __VCGLIB_TRISUBSET - -#include - -namespace vcg { -namespace tri { - - -template -struct InsertedV -{ - typedef I_MESH_TYPE IMeshType; - typedef typename IMeshType::VertexPointer VertexPointer; - typedef typename IMeshType::FacePointer FacePointer; - - InsertedV(VertexPointer _v, FacePointer _f, int _z) - : v(_v), f(_f), z(_z) - {} - - VertexPointer v; - FacePointer f; - int z; - - bool operator < (const InsertedV & o) const - { - return (v -void SubSet(S_MESH_TYPE & m, STL_CONT & subSet) -{ - std::vector< InsertedV > newVertices; - typename STL_CONT::const_iterator pfi; - typename S_MESH_TYPE::VertexIterator vi; - typename S_MESH_TYPE::FaceIterator fi; - typedef typename S_MESH_TYPE::VertexType S_VertexType; - std::vector redirect; - - - fi = vcg::tri::Allocator::AddFaces(m,subSet.size()); - for(pfi=subSet.begin(); pfi!=subSet.end(); ++pfi) - { - assert(!(*pfi)->IsD()); - (*fi).ImportData(**pfi); - for(int ii = 0 ; ii < (*fi).VN(); ++ii) - (*fi).V(ii) = (S_VertexType*)(void*)(*pfi)->V(ii); - ++fi; - } - - - for(fi=m.face.begin(); fi!=m.face.end(); ++fi) - for(int ii = 0 ; ii < (*fi).VN(); ++ii) - newVertices.push_back(InsertedV((*fi).V(ii), &(*fi),ii)); - - sort(newVertices.begin(), newVertices.end()); - - typename std::vector< InsertedV >::iterator curr, next; - int pos=0; - curr=next=newVertices.begin(); - while(next!=newVertices.end()) - { - if((*curr)!=(*next)) - pos++; - (*next).f->V((*next).z)=(typename S_MESH_TYPE::VertexPointer)pos; - curr=next; - next++; - } - - typename std::vector< InsertedV >::iterator newE=unique(newVertices.begin(), newVertices.end()); - - vi = vcg::tri::Allocator::AddVertices(m,newE-newVertices.begin()); - for(curr=newVertices.begin(); curr!=newE; ++curr,++vi) - (*vi).ImportData(*((*curr).v)); - - for(vi=m.vert.begin(); vi!=m.vert.end(); ++vi) - redirect.push_back(&(*vi)); - - for(fi=m.face.begin(); fi!=m.face.end(); ++fi) - { - for(int ii = 0 ; ii < (*fi).VN(); ++ii) - (*fi).V(ii)=redirect[(size_t)(*fi).V(ii)]; - } - m.vn=(int)m.vert.size(); - m.fn=(int)m.face.size(); -} - - -} // End Namespace TriMesh -} // End Namespace vcg - - -#endif - -