From 6c0c32ecfe11db7cb10643275af69a05ca9acb78 Mon Sep 17 00:00:00 2001 From: ganovelli Date: Fri, 1 Apr 2011 17:17:42 +0000 Subject: [PATCH] Ongoing Rearrangement of filepath delete old trimesh content --- .../local_optimization/quad_diag_collapse.h | 627 ----------------- .../local_optimization/tetra_edge_collapse.h | 288 -------- .../local_optimization/tri_edge_collapse.h | 290 -------- .../tri_edge_collapse_quadric.h | 636 ------------------ .../local_optimization/tri_edge_flip.h | 609 ----------------- 5 files changed, 2450 deletions(-) delete mode 100755 vcg/complex/trimesh/local_optimization/quad_diag_collapse.h delete mode 100644 vcg/complex/trimesh/local_optimization/tetra_edge_collapse.h delete mode 100644 vcg/complex/trimesh/local_optimization/tri_edge_collapse.h delete mode 100644 vcg/complex/trimesh/local_optimization/tri_edge_collapse_quadric.h delete mode 100644 vcg/complex/trimesh/local_optimization/tri_edge_flip.h diff --git a/vcg/complex/trimesh/local_optimization/quad_diag_collapse.h b/vcg/complex/trimesh/local_optimization/quad_diag_collapse.h deleted file mode 100755 index fdeba144..00000000 --- a/vcg/complex/trimesh/local_optimization/quad_diag_collapse.h +++ /dev/null @@ -1,627 +0,0 @@ -#ifndef QUAD_DIAGONAL_COLLAPSE_H -#define QUAD_DIAGONAL_COLLAPSE_H - -#include -#include -#include - -#include - -#include - -#include - -namespace vcg{ - namespace tri{ - - - /*! - * \brief Generic class for checking feasibility of collapses - * - */ - template - class FeasibilityCheck - { - public: - typedef typename MeshType::HEdgePointer HEdgePointer; - typedef typename TriMeshType::FaceType TriFaceType; - typedef typename vcg::GridStaticPtr GRID; - typedef typename TriMeshType::CoordType CoordType; - - static bool check_feasible(HEdgePointer hp, CoordType &V1, CoordType &V2, TriMeshType &tm, GRID &grid); - }; - - /*! - * \brief Generic class for weighting collapses - * - */ - template - class OperationWeight - { - public: - typedef typename MeshType::HEdgePointer HEdgePointer; - typedef typename TriMeshType::FaceType TriFaceType; - typedef typename vcg::GridStaticPtr GRID; - typedef typename TriMeshType::CoordType CoordType; - - static float compute_weight(HEdgePointer hp, CoordType &P, TriMeshType &tm, GRID &grid); - }; - - - /*! - * \brief Class that provides methods for checking and weighting collapses using fitmaps - * - */ - template - class FitmapsCollapse : public FeasibilityCheck, public OperationWeight - { - - protected: - - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::HEdgePointer HEdgePointer; - - typedef typename TriMeshType::FaceType TriFaceType; - typedef typename vcg::GridStaticPtr GRID; - - typedef typename TriMeshType::CoordType CoordType; - typedef typename TriMeshType::ScalarType ScalarType; - typedef typename TriMeshType::FacePointer FacePointer; - - typedef typename TriMeshType::template PerVertexAttributeHandle Fitmap_attr; - - public: - - /// Coefficient that will be multiplied with the value of the M-Fitmap - static float& Mfit_coeff() - { - static float coeff = 1.5; - return coeff; - } - - /*! Checks if an operation is feasible using M-Fitmap - * - * \param hp Pointer to an halfedge that identifies a diagonal - * \param V1 Coordinates of the first point of the diagonal - * \param V2 Coordinates of the second point of the diagonal - * \param tm Reference mesh - * \param grid Spatial index used for raycasting - * - * \return Value indicating whether diagnoal is collapsible - */ - static bool check_feasible(HEdgePointer hp, CoordType &V1, CoordType &V2, TriMeshType &tm, GRID &grid) - { - float lenght = Distance( V1, V2 ); - - Fitmap_attr M_Fit = tri::Allocator::template GetPerVertexAttribute(tm,"M-Fitmap"); - - CoordType P = (V1+V2)/2; - float fitmap = compute_fitmap(hp, P, tm, grid, M_Fit); - - return lenght <= fitmap/Mfit_coeff(); - } - - /*! Computes the weight of a diagonal using S-Fitmap - * - * \param hp Pointer to an halfedge that identifies a diagonal - * \param P Coordinates of the point on which fitmap will be computed - * \param tm Reference mesh - * \param grid Spatial index used for raycasting - * - * \return Computed weight - */ - static float compute_weight(HEdgePointer hp, CoordType &P, TriMeshType &tm, GRID &grid) - { - Fitmap_attr S_Fit = tri::Allocator::template GetPerVertexAttribute(tm,"S-Fitmap"); - - return compute_fitmap(hp, P, tm, grid, S_Fit); - } - - protected: - - /*! - * Performs the computation of a fitmap on a given point - * - * \param hp Pointer to an halfedge that identifies a diagonal - * \param P Coordinates of the point on which fitmap will be computed - * \param tm Reference mesh - * \param grid Spatial index used for raycasting - * \param attr Fitmap type (S or M) - * - * \return Computed value of the fitmap - */ - static float compute_fitmap(HEdgePointer hp, CoordType &P, TriMeshType &tm, GRID &grid, Fitmap_attr &attr) - { - CoordType N(0,0,0); - - vector vertices = HalfEdgeTopology::getVertices(hp->HFp()); - - assert(vertices.size() == 4); - - N += vcg::Normal(vertices[0]->cP(), vertices[1]->cP(), vertices[2]->cP()); - N += vcg::Normal(vertices[2]->cP(), vertices[3]->cP(), vertices[0]->cP()); - - N.Normalize(); - - CoordType C(0,0,0); - FacePointer T = getClosestFaceRay(tm, grid, P, N, &C, NULL); - - float result = 1.0; - - if(T) - { - float w0; - float w1; - float w2; - vcg::InterpolationParameters(*T, N, C, w0, w1, w2); - - float s0 = attr[T->V(0)]; - float s1 = attr[T->V(1)]; - float s2 = attr[T->V(2)]; - - result = (w0*s0 + w1*s1 + w2*s2)/(w0+w1+w2); - } - - return result; - } - - - static FacePointer getClosestFaceRay(TriMeshType &m, GRID &grid, CoordType P, CoordType raydir, CoordType* closest, ScalarType* minDist) - { - - ScalarType diag = m.bbox.Diag(); - - raydir.Normalize(); - - Ray3 ray; - - ray.SetOrigin(P); - ScalarType t; - - FacePointer f = 0; - FacePointer fr = 0; - - vector closests; - vector minDists; - vector faces; - - ray.SetDirection(-raydir); - - f = vcg::tri::DoRay(m, 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(m, 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; - - if (minDists.size() == 0) - { - if (closest) *closest=P; - if (minDist) *minDist=0; - f = 0; - } - else - { - int minI = std::min_element(minDists.begin(),minDists.end()) - minDists.begin(); - if (closest) *closest= closests[minI]; - if (minDist) *minDist= minDists[minI]; - f = faces[minI]; - } - - return f; - - } - - }; - - - - /*! - * \brief Class implementing simplification of quad meshes by diagonal collapses - * - */ - template - class QuadDiagonalCollapseBase: public LocalOptimization::LocModType - { - - protected: - - typedef Pos PosType; - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::FacePointer FacePointer; - typedef typename MeshType::HEdgePointer HEdgePointer; - typedef typename LocalOptimization::HeapElem HeapElem; - typedef typename LocalOptimization::HeapType HeapType; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::CoordType CoordType; - typedef typename TriMeshType::FaceType TriFaceType; - typedef typename vcg::GridStaticPtr GRID; - - /// Vertex returned by the collapse - VertexPointer ret; - - /// Global mark for updating - static int& GlobalMark() - { - static int im=0; - return im; - } - - /// Local mark for updating - int localMark; - - /// Priority in the heap - ScalarType _priority; - - /// Set of modified faces - set faces; - - /// Halfedge that identifies the diagonal to collapse - HEdgePointer hp; - - public: - - /// Reference mesh used for smoothing - static TriMeshType* &refMesh() - { - static TriMeshType* m = NULL; - return m; - } - - /// Spatial index for smoothing - static GRID* &grid() - { - static GRID* grid = NULL; - return grid; - } - - /// Number of smoothing iterations to be performed - static unsigned int &smoothing_iterations() - { - static unsigned int iterations = 5; - return iterations; - } - - /// Default Constructor - QuadDiagonalCollapseBase(){} - - /*! - * Constructor - * - * \param he Pointer to an halfedge representing a diagonal - * \param mark Temporal mark of the operation - */ - QuadDiagonalCollapseBase(HEdgePointer he, int mark) - { - localMark = mark; - hp = he; - _priority = ComputePriority(); - } - - ~QuadDiagonalCollapseBase() - { - faces.clear(); - } - - /*! - * Computes priority of the operation as the length of the diagonal - * - * \return Priority - */ - ScalarType ComputePriority() - { - CoordType V1 = hp->HVp()->cP(); - CoordType V2 = hp->HNp()->HNp()->HVp()->cP(); - - _priority = Distance( V1, V2 ); - return _priority; - } - - virtual const char *Info(MeshType &m) - { - static char buf[60]; - sprintf(buf,"(%d - %d) %g\n", hp->HVp()-&m.vert[0], hp->HNp()->HNp()->HVp()-&m.vert[0], -_priority); - return buf; - } - - /*! - * Performs the collapse and the optimizations - * - * \param m Mesh - * - */ - inline void Execute(MeshType &m) - { - - // Collapse the diagonal - ret = HalfEdgeTopology::diagonal_collapse_quad(m,hp->HFp(), hp->HVp()); - - if(ret->VHp()) - { - set tmp = HalfEdgeTopology::getFaces(ret); - - vector incident_faces = HalfEdgeTopology::get_incident_faces(ret,ret->VHp()); - - faces.insert(incident_faces.begin(), incident_faces.end()); - - HalfedgeQuadClean::remove_doublets(m, faces); - - // Optimization by edge rotations - if(!ret->IsD()) - { - vector hedges = HalfEdgeTopology::get_incident_hedges(ret,ret->VHp()); - - HalfedgeQuadClean:: template flip_edges(m, hedges, faces); - } - - faces.insert(tmp.begin(), tmp.end()); - - // Set of all vertices to smooth - set vertices; - - for(typename set::iterator fi = faces.begin(); fi != faces.end(); ++fi) - { - if(*fi) - { - if( !((*fi)->IsD())) - { - vector aux = HalfEdgeTopology::getVertices(*fi); - - vertices.insert(aux.begin(),aux.end()); - } - } - } - - - // Smoothing - for(unsigned int i = 0; i < smoothing_iterations(); i++) - { - for(typename set::iterator vi = vertices.begin(); vi!= vertices.end(); ++vi) - if(!HalfEdgeTopology::isBorderVertex(*vi)) - Smooth::VertexCoordLaplacianReproject(m,*grid(), *refMesh(),*vi); - } - - - // Add all faces modified by smoothing into the set of modified faces - for(typename set::iterator vi = vertices.begin(); vi!= vertices.end(); ++vi) - { - vector tmp_faces = HalfEdgeTopology::get_incident_faces(*vi); - - faces.insert(tmp_faces.begin(), tmp_faces.end()); - } - - } - - - } - - /*! - * Updates the heap of operations. - * For each modified face inserts into the heap two consecutive halfedges representing the two diagonals - * - * \param h_ret Heap to be updated - * - */ - inline void UpdateHeap(HeapType & h_ret) - { - - GlobalMark()++; - - for(typename set::iterator fi = faces.begin(); fi != faces.end(); ++fi) - { - if(*fi) - { - if( !((*fi)->IsD())) - { - (*fi)->IMark() = GlobalMark(); - - HEdgePointer start_he = (*fi)->FHp(); - - h_ret.push_back( HeapElem( new MYTYPE( start_he, GlobalMark() ) ) ); - std::push_heap( h_ret.begin(),h_ret.end() ); - - h_ret.push_back( HeapElem( new MYTYPE( start_he->HNp(), GlobalMark() ) ) ); - std::push_heap( h_ret.begin(),h_ret.end() ); - } - } - } - } - - - ModifierType IsOfType() - { - return QuadDiagCollapseOp; - } - - /*! - * Checks if the operation can be done without generation of degenerate configurations - * - * \return Value indicating whether the operation can be performed - */ - inline bool IsFeasible() - { - FacePointer fp = hp->HFp(); - - if(!fp) - return false; - - if(fp->IsD() || fp->VN() !=4) - return false; - - return ( HalfEdgeTopology::check_diagonal_collapse_quad(hp)); - - } - - /*! - * Checks if the operation is up to date - * - * \return Value indicating whether operation is up to date - */ - inline bool IsUpToDate() - { - FacePointer fp = hp->HFp(); - - if(fp) - return (!hp->IsD() && localMark >= fp->IMark() ); - - return false; - - } - - /*! - * Gets the priority of the operation - * - * \return Value indicating the priority - */ - virtual ScalarType Priority() const - { - return _priority; - } - - /*! - * Initializes a heap with all the possible diagonal collapses of the mesh - * For each face inserts two consecutive halfedges representing the two diagonals - * - * \param m Mesh - * \param h_ret heap to be initialized - * - */ - static void Init(MeshType &m,HeapType &h_ret) - { - // Grid and reference mesh must be initialized - assert(grid()); - assert(refMesh()); - - assert(!HalfedgeQuadClean::has_doublets(m)); - assert(!HalfedgeQuadClean::has_singlets(m)); - - vcg::tri::InitFaceIMark(m); - - h_ret.clear(); - - typename MeshType::FaceIterator fi; - for(fi = m.face.begin(); fi != m.face.end();++fi) - { - if(!(*fi).IsD()) - { - - h_ret.push_back( HeapElem(new MYTYPE( (*fi).FHp(), IMark(m)))); - - h_ret.push_back( HeapElem(new MYTYPE( (*fi).FHp()->HNp(), IMark(m)))); - - } - } - - } - - - }; - - /*! - * \brief Class implementing simplification of quad meshes by diagonal collapses - * priority of the operations is weighted with a value computed by class WeightType - * Feasibility is checked with class CheckType - * - */ - template - class QuadDiagonalCollapse: public QuadDiagonalCollapseBase - { - - protected: - - typedef Pos PosType; - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::FacePointer FacePointer; - typedef typename MeshType::HEdgePointer HEdgePointer; - typedef typename LocalOptimization::HeapElem HeapElem; - typedef typename LocalOptimization::HeapType HeapType; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::CoordType CoordType; - - typedef typename TriMeshType::FaceType TriFaceType; - typedef typename vcg::GridStaticPtr GRID; - - public: - - /// Default constructor - QuadDiagonalCollapse(){} - - /*! - * Constructor - * - * \param he Pointer to an halfedge representing a diagonal - * \param mark Temporal mark of the operation - */ - QuadDiagonalCollapse(HEdgePointer he, int mark) - { - this->localMark = mark; - this->hp = he; - this->_priority = this->ComputePriority(); - } - - /*! - * Computes priority of the operation as length * weight - * - * \return Priority - */ - ScalarType ComputePriority() - { - CoordType V1 = this->hp->HVp()->cP(); - CoordType V2 = this->hp->HNp()->HNp()->HVp()->cP(); - - CoordType P = (V1+V2)/2; - float weight = WeightType::compute_weight(this->hp, P, *(this->refMesh()), *(this->grid())); - - this->_priority = Distance( V1, V2 ) * weight; - return this->_priority; - } - - /*! - * Checks if the operation can be done without generation of degenerate configurations - * - * \return Value indicating whether the operation can be performed - */ - bool IsFeasible() - { - FacePointer fp = this->hp->HFp(); - - if(!fp) - return false; - - if(fp->IsD() || fp->VN() !=4) - return false; - - if(!HalfEdgeTopology::check_diagonal_collapse_quad(this->hp)) - return false; - - CoordType V1 = this->hp->HVp()->cP(); - CoordType V2 = this->hp->HNp()->HNp()->HVp()->cP(); - - return CheckType::check_feasible(this->hp, V1, V2, *(this->refMesh()), *(this->grid())); - - } - - }; - - - }//end namespace tri -}//end namespace vcg - -#endif // QUAD_DIAGONAL_COLLAPSE_H diff --git a/vcg/complex/trimesh/local_optimization/tetra_edge_collapse.h b/vcg/complex/trimesh/local_optimization/tetra_edge_collapse.h deleted file mode 100644 index abc0e1de..00000000 --- a/vcg/complex/trimesh/local_optimization/tetra_edge_collapse.h +++ /dev/null @@ -1,288 +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 -****************************************************************************/ - -#ifndef __VCG_DECIMATION_COLLAPSE -#define __VCG_DECIMATION_COLLAPSE - -#include -#include -#include -#include - - -struct FAIL{ - static int VOL(){static int vol=0; return vol++;} - static int LKF(){static int lkf=0; return lkf++;} - static int LKE(){static int lke=0; return lke++;} - static int LKV(){static int lkv=0; return lkv++;} - static int OFD(){static int ofd=0; return ofd++;} - static int BOR(){static int bor=0; return bor++;} - -}; - -namespace vcg{ -namespace tetra{ - -/** \addtogroup tetramesh */ -/*@{*/ -/// This Class is specialization of LocalModification for the edge collapse -/// It wraps the atomic operation EdgeCollapse to be used in a optimizatin routine. -/// Note that it has knowledge of the heap of the class LocalOptimization because -/// it is responsible of updating it after a collapse has been performed - -template -class TetraEdgeCollapse: public LocalOptimization::LocModType -{ - - /// The tetrahedral mesh type - //typedef typename TETRA_MESH_TYPE TETRA_MESH_TYPE; - /// The tetrahedron type - typedef typename TETRA_MESH_TYPE::TetraType TetraType; - /// The vertex type - typedef typename TetraType::VertexType VertexType; - /// The coordinate type - typedef typename TetraType::VertexType::CoordType CoordType; - /// The scalar type - typedef typename TETRA_MESH_TYPE::VertexType::ScalarType ScalarType; - /////the base type class - //typedef typename vcg::tri::LocalModification LocalMod; - /// The HEdgePos type - typedef Pos PosType; - /// The HEdgePos Loop type - typedef PosLoop PosLType; - /// definition of the heap element - typedef typename LocalOptimization::HeapElem HeapElem; -private: - -///the new point that substitute the edge -Point3 _NewPoint; -///the pointer to edge collapser method -vcg::tetra::EdgeCollapse _EC; -///mark for up_dating -static int& _Imark(){ static int im=0; return im;} -///the pos of collapse -PosType pos; -///pointer to vertex that remain -VertexType *vrem; -/// priority in the heap -ScalarType _priority; - -public: -/// Default Constructor - TetraEdgeCollapse() - {} - -///Constructor with postype - TetraEdgeCollapse(PosType p,int mark) - { - _Imark() = mark; - pos=p; - _priority = _AspectRatioMedia(p); - } - - ~TetraEdgeCollapse() - {} - -private: - -///Return the aspect Ratio media of the tetrahedrons -///that share the adge to collapse -ScalarType _AspectRatioMedia(PosType p) -{ - PosLType posl=PosLType(p.T(),p.F(),p.E(),p.V()); - posl.Reset(); - int num=0; - ScalarType ratio_media=0.f; - while(!posl.LoopEnd()) - { - ratio_media+=posl.T()->AspectRatio(); - posl.NextT(); - num++; - } - ratio_media=ratio_media/num; - return (ratio_media); -} - - -///Modify pos and alfa to obtain the collapse that minimize the error -ScalarType _VolumePreservingError(PosType &pos,CoordType &new_point,int nsteps) -{ - VertexType *ve0=(pos.T()->V(Tetra::VofE(pos.E(),0))); - VertexType *ve1=(pos.T()->V(Tetra::VofE(pos.E(),1))); - bool ext_v0=ve0->IsB(); - bool ext_v1=ve1->IsB(); - - ScalarType best_error=0.f; - if ((ext_v0)&&(!ext_v1)) - new_point=ve0->P(); - else - if ((!ext_v0)&&(ext_v1)) - new_point=ve1->P(); - else - if ((!ext_v0)&&(!ext_v1)) - {/*CoordType g; - g.SetZero(); - g+=ve0->cP(); - g+=ve1->cP(); - g/=2;*/ - new_point=(ve0->cP()+ve1->cP())/2.f; - } - else - if ((ext_v0)&&(ext_v1))//both are external vertex - { - ScalarType step=1.f/(nsteps-1); - ScalarType Vol_Original=_EC.VolumeOriginal(); - for (int i=0;icP()*alfatemp; - //g+=ve1->cP()*(1-alfatemp); - //CoordType newPTemp=g; - CoordType newPTemp=(ve0->cP()*alfatemp) +(ve1->cP()*(1.f-alfatemp)); - //the error is the absolute value of difference of volumes - ScalarType error=fabs(Vol_Original-_EC.VolumeSimulateCollapse(pos,newPTemp)); - if(error %i %f\n", pos.()-&m.vert[0], pos.VFlip()-&m.vert[0],_priority); - return buf; - } - - ScalarType ComputePriority() - { - return (_priority = _AspectRatioMedia(this->pos)); - } - - ScalarType ComputeError() - { - vrem=(pos.T()->V(Tetra::VofE(pos.E(),0))); - return (_VolumePreservingError(pos,_NewPoint,5));// magic number....parametrize! - } - - void Execute(TETRA_MESH_TYPE &tm) - { - // _EC.FindSets(pos); - assert(!vrem->IsD()); - int del=_EC.DoCollapse(pos,_NewPoint); - tm.tn-=del; - tm.vn-=1; - } - - void UpdateHeap(typename LocalOptimization::HeapType & h_ret) - { - assert(!vrem->IsD()); - _Imark()++; - VTIterator VTi(vrem->VTb(),vrem->VTi()); - while (!VTi.End()) - { - VTi.Vt()->ComputeVolume(); - for (int j=0;j<6;j++) - { - vcg::tetra::Pos p=Pos(VTi.Vt(),Tetra::FofE(j,0),j,Tetra::VofE(j,0)); - assert(!p.T()->V(p.V())->IsD()); - assert(!p.T()->IsD()); - h_ret.push_back(HeapElem(new TetraEdgeCollapse(p,_Imark()))); - std::push_heap(h_ret.begin(),h_ret.end()); - // update the mark of the vertices - VTi.Vt()->V(Tetra::VofE(j,0))->IMark() = _Imark(); - } - ++VTi; - } - } - - /// return the type of operation - - ModifierType IsOfType(){ return TetraEdgeCollapseOp;} - - bool IsFeasible(){ - vcg::tetra::EdgeCollapse::Reset(); - _EC.FindSets(pos); - ComputeError(); - return(_EC.CheckPreconditions(pos,_NewPoint)); - } - - bool IsUpToDate(){ - if (!pos.T()->IsD()) - { - VertexType *v0=pos.T()->V(Tetra::VofE(pos.E(),0)); - VertexType *v1=pos.T()->V(Tetra::VofE(pos.E(),1)); - assert(!v0->IsD()); - assert(!v1->IsD()); - if(! (( (!v0->IsD()) && (!v1->IsD())) && - _Imark()>=v0->IMark() && - _Imark()>=v1->IMark())) - { - FAIL::OFD(); - return false; - } - else - return true; - } - else - return false; - } - - virtual ScalarType Priority() const { - return _priority; - } - - /// perform initialization - static void Init(TETRA_MESH_TYPE &m,typename LocalOptimization::HeapType& h_ret){ - h_ret.clear(); - typename TETRA_MESH_TYPE::TetraIterator ti; - for(ti = m.tetra.begin(); ti != m.tetra.end();++ti) - if(!(*ti).IsD()){ - (*ti).ComputeVolume(); - for (int j=0;j<6;j++) - { - PosType p=PosType(&*ti,Tetra::FofE(j,0),j,Tetra::VofE(j,0)); - assert(!p.T()->V(p.V())->IsD()); - assert(!p.T()->IsD()); - h_ret.push_back(HeapElem(new TetraEdgeCollapse(p,m.IMark))); - } - } - } - -}; -}//end namespace tetra -}//end namespace vcg -#endif diff --git a/vcg/complex/trimesh/local_optimization/tri_edge_collapse.h b/vcg/complex/trimesh/local_optimization/tri_edge_collapse.h deleted file mode 100644 index 1f7ab86c..00000000 --- a/vcg/complex/trimesh/local_optimization/tri_edge_collapse.h +++ /dev/null @@ -1,290 +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.19 2006/10/15 07:31:21 cignoni - typenames and qualifiers for gcc compliance - - Revision 1.18 2006/10/09 20:09:40 cignoni - Changed some access to VertexFaceIterator to reflect the shorter new operators. - - Revision 1.17 2005/10/12 10:44:01 cignoni - Now creation of new edge use Ordered() constructor to comply the fact that the basic collapse is simmetric. - - Revision 1.16 2005/01/19 10:35:28 cignoni - Better management of symmetric/asymmetric edge collapses - - Revision 1.15 2004/12/10 01:03:53 cignoni - better comments and removed logging - - Revision 1.14 2004/11/23 10:34:23 cignoni - passed parameters by reference in many funcs and gcc cleaning - - Revision 1.13 2004/10/25 16:28:32 ganovelli - pos to edge - - Revision 1.12 2004/09/15 11:16:02 ganovelli - changed P() to cP() - - Revision 1.11 2004/09/09 13:23:01 ponchio - Header guards typo - - Revision 1.10 2004/09/09 13:01:12 ponchio - Linux compatible path in #include - - Revision 1.9 2004/09/08 15:13:29 ganovelli - changes for gc - - Revision 1.8 2004/09/08 14:33:31 ganovelli - *** empty log message *** - - -****************************************************************************/ - -#ifndef __VCG_DECIMATION_TRICOLLAPSE -#define __VCG_DECIMATION_TRICOLLAPSE - -#include -#include -#include - - -namespace vcg{ -namespace tri{ - -/** \addtogroup trimesh */ -/*@{*/ -/// This Class is specialization of LocalModification for the edge collapse. -/// It wraps the atomic operation EdgeCollapse to be used in a optimizatin routine. -/// Note that it has knowledge of the heap of the class LocalOptimization because -/// it is responsible of updating it after a collapse has been performed; -/// This is the base class of all the specialized collapse classes like for example Quadric Edge Collapse. -/// Each derived class - -template -class TriEdgeCollapse: public LocalOptimization::LocModType , public EdgeCollapse -{ -public: - /// static data to gather statistical information about the reasons of collapse failures - class FailStat { - public: - static int &Volume() {static int vol=0; return vol;} - static int &LinkConditionFace(){static int lkf=0; return lkf;} - static int &LinkConditionEdge(){static int lke=0; return lke;} - static int &LinkConditionVert(){static int lkv=0; return lkv;} - static int &OutOfDate() {static int ofd=0; return ofd;} - static int &Border() {static int bor=0; return bor;} - static void Init() - { - Volume() =0; - LinkConditionFace()=0; - LinkConditionEdge()=0; - LinkConditionVert()=0; - OutOfDate() =0; - Border() =0; - } -}; -protected: - typedef typename TriMeshType::FaceType FaceType; - typedef typename TriMeshType::FaceType::VertexType VertexType; - typedef typename VertexType::EdgeType EdgeType; - typedef typename FaceType::VertexType::CoordType CoordType; - typedef typename TriMeshType::VertexType::ScalarType ScalarType; - typedef typename LocalOptimization::HeapElem HeapElem; - typedef typename LocalOptimization::HeapType HeapType; - - TriMeshType *mt; - ///the pair to collapse - EdgeType pos; - - ///mark for up_dating - static int& GlobalMark(){ static int im=0; return im;} - - ///mark for up_dating - int localMark; - - /// priority in the heap - ScalarType _priority; - - public: - /// Default Constructor - inline TriEdgeCollapse() - {} - ///Constructor with postype - inline TriEdgeCollapse(const EdgeType &p, int mark) - { - localMark = mark; - pos=p; - _priority = ComputePriority(); - } - - ~TriEdgeCollapse() - {} - -private: - - -public: - - - inline ScalarType ComputePriority() - { - _priority = Distance(pos.V(0)->cP(),pos.V(1)->cP()); - return _priority; - } - - virtual const char *Info(TriMeshType &m) { - mt = &m; - static char buf[60]; - sprintf(buf,"%i -> %i %g\n", int(pos.V(0)-&m.vert[0]), int(pos.V(1)-&m.vert[0]),-_priority); - return buf; - } - - inline void Execute(TriMeshType &m) - { - CoordType MidPoint=(pos.V(0)->P()+pos.V(1)->P())/2.0; - DoCollapse(m, pos, MidPoint); - } - - static bool IsSymmetric() { return true;} - - - // This function is called after an action to re-add in the heap elements whose priority could have been changed. - // in the plain case we just put again in the heap all the edges around the vertex resulting from the previous collapse: v[1]. - // if the collapse is not symmetric you should add also backward edges (because v0->v1 collapse could be different from v1->v0) - - inline void UpdateHeap(HeapType & h_ret) - { - GlobalMark()++; int nn=0; - VertexType *v[2]; - v[0]= pos.V(0);v[1]=pos.V(1); - v[1]->IMark() = GlobalMark(); - - // First loop around the remaining vertex to unmark visited flags - vcg::face::VFIterator vfi(v[1]); - while (!vfi.End()){ - vfi.V1()->ClearV(); - vfi.V2()->ClearV(); - ++vfi; - } - - // Second Loop: add all the outgoing edges around v[1] - // for each face add the two edges outgoing from v[1] and not visited. - vfi = face::VFIterator(v[1]); - while (!vfi.End()) - { - assert(!vfi.F()->IsD()); - for (int j=0;j<3;j++) - { - if( !(vfi.V1()->IsV()) && (vfi.V1()->IsRW())) - { - vfi.V1()->SetV(); - h_ret.push_back(HeapElem(new MYTYPE(EdgeType( vfi.V(),vfi.V1() ),GlobalMark()))); - std::push_heap(h_ret.begin(),h_ret.end()); - if(! this->IsSymmetric()){ - h_ret.push_back(HeapElem(new MYTYPE(EdgeType( vfi.V1(),vfi.V()),GlobalMark()))); - std::push_heap(h_ret.begin(),h_ret.end()); - } - } - if( !(vfi.V2()->IsV()) && (vfi.V2()->IsRW())) - { - vfi.V2()->SetV(); - h_ret.push_back(HeapElem(new MYTYPE(EdgeType(vfi.F()->V(vfi.I()),vfi.F()->V2(vfi.I())),GlobalMark()))); - std::push_heap(h_ret.begin(),h_ret.end()); - if(! this->IsSymmetric()){ - h_ret.push_back(HeapElem(new MYTYPE(EdgeType (vfi.F()->V1(vfi.I()),vfi.F()->V(vfi.I())),GlobalMark()))); - std::push_heap(h_ret.begin(),h_ret.end()); - } - } - // if(vfi.V1()->IsRW() && vfi.V2()->IsRW() ) -// { -// h_ret.push_back(HeapElem(new MYTYPE(EdgeType(vfi.V1(),vfi.V2()),this->GlobalMark()))); -// std::push_heap(h_ret.begin(),h_ret.end()); -// if(IsSymmetric()){ -// h_ret.push_back(HeapElem(new MYTYPE(EdgeType(vfi.V2(),vfi.V1()), this->GlobalMark()))); -// std::push_heap(h_ret.begin(),h_ret.end()); -// } -// } - - } - ++vfi;nn++; - } -// printf("ADDED %d\n",nn); - } - - ModifierType IsOfType(){ return TriEdgeCollapseOp;} - - inline bool IsFeasible(){ - return LinkConditions(pos); - } - - inline bool IsUpToDate(){ - // if(pos.V(1)->IsD()) { - // ++FailStat::OutOfDate(); - // return false; - //} - // - // if(pos.V(1)->IsD()) { - // ++FailStat::OutOfDate(); - // return false; - //} - - VertexType *v0=pos.V(0); - VertexType *v1=pos.V(1); - - //if(! (( (!v0->IsD()) && (!v1->IsD())) && - // localMark>=v0->IMark() && - // localMark>=v1->IMark())) - if( v0->IsD() || v1->IsD() || - localMark < v0->IMark() || - localMark < v1->IMark() ) - { - ++FailStat::OutOfDate(); - return false; - } - return true; - } - - virtual ScalarType Priority() const { - return _priority; - } - - static void Init(TriMeshType&m,HeapType&h_ret){ - h_ret.clear(); - typename TriMeshType::FaceIterator fi; - for(fi = m.face.begin(); fi != m.face.end();++fi) - if(!(*fi).IsD()){ - for (int j=0;j<3;j++) - { - EdgeType p=EdgeType::OrderedEdge((*fi).V(j),(*fi).V((j+1)%3)); - h_ret.push_back(HeapElem(new MYTYPE(p, IMark(m)))); - //printf("Inserting in heap coll %3i ->%3i %f\n",p.V()-&m.vert[0],p.VFlip()-&m.vert[0],h_ret.back().locModPtr->Priority()); - } - } - } - -}; -}//end namespace tri -}//end namespace vcg - -#endif diff --git a/vcg/complex/trimesh/local_optimization/tri_edge_collapse_quadric.h b/vcg/complex/trimesh/local_optimization/tri_edge_collapse_quadric.h deleted file mode 100644 index 58afcaa3..00000000 --- a/vcg/complex/trimesh/local_optimization/tri_edge_collapse_quadric.h +++ /dev/null @@ -1,636 +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.14 2007/03/22 11:07:16 cignoni -Solved an issue related to different casting double-float between gcc 3 and gcc 4 - -Revision 1.13 2007/02/25 09:20:10 cignoni -Added Rad to the NormalThr Option and removed a bug in multiple exectuion of non optimal simplification (missing an isD check) - -Revision 1.12 2007/01/19 09:13:14 cignoni -Added Finalize() method to the interface, corrected minor bugs on border preserving and postsimplification cleanup -Avoided double make_heap (it is done only in the local_optimization init) - -Revision 1.11 2006/10/15 07:31:21 cignoni -typenames and qualifiers for gcc compliance - -Revision 1.10 2006/10/09 20:12:55 cignoni -Heavyly restructured for meshlab inclusion. Now the access to the quadric elements are mediated by a static helper class. - -Revision 1.9 2006/10/07 17:20:25 cignoni -Updated to the new style face->Normal() becomes Normal(face) - -Revision 1.8 2005/10/02 23:19:36 cignoni -Changed the sign of the priority of a collapse. Now it is its the error as it should (and not -error) - -Revision 1.7 2005/04/14 11:35:07 ponchio -*** empty log message *** - -Revision 1.6 2005/01/19 10:35:28 cignoni -Better management of symmetric/asymmetric edge collapses - -Revision 1.5 2004/12/10 01:07:15 cignoni -Moved param classes inside; added support for optimal placement and symmetric; added update heap also here (not only in the base class) - -Revision 1.4 2004/11/23 10:34:23 cignoni -passed parameters by reference in many funcs and gcc cleaning - -Revision 1.3 2004/10/25 07:07:56 ganovelli -A vcg.::Pos was used to implement the collapse type. CHanged -to vcg::Edge - -Revision 1.2 2004/09/29 17:08:16 ganovelli -corrected error in -error (see localoptimization) - - -****************************************************************************/ - - - - -#ifndef __VCG_TRIMESHCOLLAPSE_QUADRIC__ -#define __VCG_TRIMESHCOLLAPSE_QUADRIC__ - -#include -#include -#include -#include -#include -#include -#include - - -namespace vcg{ -namespace tri{ - - - - -/** - This class describe Quadric based collapse operation. - - Requirements: - - Vertex - must have: - incremental mark - VF topology - - must have: - members - - QuadricType Qd(); - - ScalarType W() const; - A per-vertex Weight that can be used in simplification - lower weight means that error is lowered, - standard: return W==1.0 - - void Merge(MESH_TYPE::vertex_type const & v); - Merges the attributes of the current vertex with the ones of v - (e.g. its weight with the one of the given vertex, the color ect). - Standard: void function; - - OtherWise the class should be templated with a static helper class that helps to retrieve these functions. - If the vertex class exposes these functions a default static helper class is provided. - -*/ - //**Helper CLASSES**// - template - class QInfoStandard - { - public: - QInfoStandard(){}; - static void Init(){}; - static math::Quadric &Qd(VERTEX_TYPE &v) {return v.Qd();} - static math::Quadric &Qd(VERTEX_TYPE *v) {return v->Qd();} - static typename VERTEX_TYPE::ScalarType W(VERTEX_TYPE */*v*/) {return 1.0;}; - static typename VERTEX_TYPE::ScalarType W(VERTEX_TYPE &/*v*/) {return 1.0;}; - static void Merge(VERTEX_TYPE & v_dest, VERTEX_TYPE const & v_del){}; - }; - - -class TriEdgeCollapseQuadricParameter -{ -public: - double QualityThr; // all - double BoundaryWeight; - double NormalThrRad; - double CosineThr; - double QuadricEpsilon; - double ScaleFactor; - bool UseArea; - bool UseVertexWeight; - bool NormalCheck; - bool QualityCheck; - bool OptimalPlacement; - bool MemoryLess; - bool QualityWeight; - bool ScaleIndependent; - //*********************** - bool QualityQuadric; // During the initialization manage all the edges as border edges adding a set of additional quadrics that are useful mostly for keeping face aspect ratio good. - bool PreserveTopology; - bool PreserveBoundary; - bool MarkComplex; - bool FastPreserveBoundary; - bool SafeHeapUpdate; -}; - - -template > -class TriEdgeCollapseQuadric: public TriEdgeCollapse< TriMeshType, MYTYPE> -{ -public: - typedef typename vcg::tri::TriEdgeCollapse< TriMeshType, MYTYPE > TEC; - typedef typename TEC::EdgeType EdgeType; - typedef typename TriEdgeCollapse::HeapType HeapType; - typedef typename TriEdgeCollapse::HeapElem HeapElem; - typedef typename TriMeshType::CoordType CoordType; - typedef typename TriMeshType::ScalarType ScalarType; - typedef math::Quadric< double > QuadricType; - typedef typename TriMeshType::FaceType FaceType; - typedef typename TriMeshType::VertexType VertexType; - typedef TriEdgeCollapseQuadricParameter QParameter; - typedef HelperType QH; - - static QParameter & Params(){ - static QParameter p; - return p; - } - enum Hint { - HNHasFFTopology = 0x0001, // La mesh arriva con la topologia ff gia'fatta - HNHasVFTopology = 0x0002, // La mesh arriva con la topologia bf gia'fatta - HNHasBorderFlag = 0x0004 // La mesh arriva con i flag di bordo gia' settati - }; - - static int & Hnt(){static int hnt; return hnt;} // the current hints - - static void SetHint(Hint hn) { Hnt() |= hn; } - static void ClearHint(Hint hn) { Hnt()&=(~hn);} - static bool IsSetHint(Hint hn) { return (Hnt()&hn)!=0; } - - // puntatori ai vertici che sono stati messi non-w per preservare il boundary - static std::vector & WV(){ - static std::vector _WV; return _WV; - }; - - inline TriEdgeCollapseQuadric(const EdgeType &p, int i) - //:TEC(p,i){} - { - this->localMark = i; - this->pos=p; - this->_priority = ComputePriority(); - } - - - inline bool IsFeasible(){ - bool res = ( !Params().PreserveTopology || LinkConditions(this->pos) ); - if(!res) ++( TriEdgeCollapse< TriMeshType,MYTYPE>::FailStat::LinkConditionEdge() ); - return res; - } - - void Execute(TriMeshType &m) - { CoordType newPos; - if(Params().OptimalPlacement) newPos= static_cast(this)->ComputeMinimal(); - else newPos=this->pos.V(1)->P(); - //this->pos.V(1)->Qd()+=this->pos.V(0)->Qd(); - QH::Qd(this->pos.V(1))+=QH::Qd(this->pos.V(0)); - //int FaceDel= - DoCollapse(m, this->pos, newPos); // v0 is deleted and v1 take the new position - //m.fn-=FaceDel; - //--m.vn; - } - - - - // Final Clean up after the end of the simplification process - static void Finalize(TriMeshType &m, HeapType& /*h_ret*/) - { - // if the mesh was prepared with precomputed borderflags - // correctly set them again. - if(IsSetHint(HNHasBorderFlag) ) - vcg::tri::UpdateFlags::FaceBorderFromVF(m); - - // If we had the boundary preservation we should clean up the writable flags - if(Params().FastPreserveBoundary) - { - typename TriMeshType::VertexIterator vi; - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - if(!(*vi).IsD()) (*vi).SetW(); - } - if(Params().PreserveBoundary) - { - typename std::vector::iterator wvi; - for(wvi=WV().begin();wvi!=WV().end();++wvi) - if(!(*wvi)->IsD()) (*wvi)->SetW(); - } - } - - static void Init(TriMeshType &m,HeapType&h_ret){ - - typename TriMeshType::VertexIterator vi; - typename TriMeshType::FaceIterator pf; - - EdgeType av0,av1,av01; - Params().CosineThr=cos(Params().NormalThrRad); - - if(!IsSetHint(HNHasVFTopology) ) vcg::tri::UpdateTopology::VertexFace(m); - - if(Params().MarkComplex) { - vcg::tri::UpdateTopology::FaceFace(m); - vcg::tri::UpdateFlags::FaceBorderFromFF(m); - vcg::tri::UpdateTopology::VertexFace(m); - } // e' un po' piu' lenta ma marca i vertici complex - else - if(!IsSetHint(HNHasBorderFlag) ) - vcg::tri::UpdateFlags::FaceBorderFromVF(m); - - if(Params().FastPreserveBoundary) - { - for(pf=m.face.begin();pf!=m.face.end();++pf) - if( !(*pf).IsD() && (*pf).IsW() ) - for(int j=0;j<3;++j) - if((*pf).IsB(j)) - { - (*pf).V(j)->ClearW(); - (*pf).V1(j)->ClearW(); - } - } - - if(Params().PreserveBoundary) - { - WV().clear(); - for(pf=m.face.begin();pf!=m.face.end();++pf) - if( !(*pf).IsD() && (*pf).IsW() ) - for(int j=0;j<3;++j) - if((*pf).IsB(j)) - { - if((*pf).V(j)->IsW()) {(*pf).V(j)->ClearW(); WV().push_back((*pf).V(j));} - if((*pf).V1(j)->IsW()) {(*pf).V1(j)->ClearW();WV().push_back((*pf).V1(j));} - } - } - - InitQuadric(m); - - // Initialize the heap with all the possible collapses - if(IsSymmetric()) - { // if the collapse is symmetric (e.g. u->v == v->u) - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - if(!(*vi).IsD() && (*vi).IsRW()) - { - vcg::face::VFIterator x; - for( x.F() = (*vi).VFp(), x.I() = (*vi).VFi(); x.F()!=0; ++ x){ - x.V1()->ClearV(); - x.V2()->ClearV(); - } - for( x.F() = (*vi).VFp(), x.I() = (*vi).VFi(); x.F()!=0; ++x ) - { - assert(x.F()->V(x.I())==&(*vi)); - if((x.V0()IsRW() && !x.V1()->IsV()){ - x.V1()->SetV(); - h_ret.push_back(HeapElem(new MYTYPE(EdgeType(x.V0(),x.V1()),TriEdgeCollapse< TriMeshType,MYTYPE>::GlobalMark() ))); - } - if((x.V0()IsRW()&& !x.V2()->IsV()){ - x.V2()->SetV(); - h_ret.push_back(HeapElem(new MYTYPE(EdgeType(x.V0(),x.V2()),TriEdgeCollapse< TriMeshType,MYTYPE>::GlobalMark() ))); - } - } - } - } - else - { // if the collapse is A-symmetric (e.g. u->v != v->u) - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - if(!(*vi).IsD() && (*vi).IsRW()) - { - vcg::face::VFIterator x; - UnMarkAll(m); - for( x.F() = (*vi).VFp(), x.I() = (*vi).VFi(); x.F()!=0; ++ x) - { - assert(x.F()->V(x.I())==&(*vi)); - if(x.V()->IsRW() && x.V1()->IsRW() && !IsMarked(m,x.F()->V1(x.I()))){ - h_ret.push_back( HeapElem( new MYTYPE( EdgeType (x.V(),x.V1()),TriEdgeCollapse< TriMeshType,MYTYPE>::GlobalMark()))); - } - if(x.V()->IsRW() && x.V2()->IsRW() && !IsMarked(m,x.F()->V2(x.I()))){ - h_ret.push_back( HeapElem( new MYTYPE( EdgeType (x.V(),x.V2()),TriEdgeCollapse< TriMeshType,MYTYPE>::GlobalMark()))); - } - } - } - } -} - static float HeapSimplexRatio() {return IsSymmetric()?5.0f:9.0f;} - static bool IsSymmetric() {return Params().OptimalPlacement;} - static bool IsVertexStable() {return !Params().OptimalPlacement;} - static void SetDefaultParams(){ - Params().UseArea=true; - Params().UseVertexWeight=false; - Params().NormalCheck=false; - Params().NormalThrRad=M_PI/2; - Params().QualityCheck=true; - Params().QualityThr=.1; - Params().BoundaryWeight=.5; - Params().QualityQuadric=false; - Params().OptimalPlacement=true; - Params().ScaleIndependent=true; - Params().QualityWeight=false; - Params().QuadricEpsilon =1e-15; - Params().ScaleFactor=1.0; - - Params().PreserveTopology = false; - } - -///* -// Funzione principale di valutazione dell'errore del collasso. -// In pratica simula il collasso vero e proprio. -// -// Da ottimizzare il ciclo sulle normali (deve sparire on e si deve usare per face normals) -//*/ - ScalarType ComputePriority() { - ScalarType error; - typename vcg::face::VFIterator x; - std::vector on; // original normals - typename TriMeshType::VertexType * v[2]; - v[0] = this->pos.V(0); - v[1] = this->pos.V(1); - - if(Params().NormalCheck){ // Compute maximal normal variation - // store the old normals for non-collapsed face in v0 - for(x.F() = v[0]->VFp(), x.I() = v[0]->VFi(); x.F()!=0; ++x ) // for all faces in v0 - if(x.F()->V(0)!=v[1] && x.F()->V(1)!=v[1] && x.F()->V(2)!=v[1] ) // skip faces with v1 - on.push_back(NormalizedNormal(*x.F())); - // store the old normals for non-collapsed face in v1 - for(x.F() = v[1]->VFp(), x.I() = v[1]->VFi(); x.F()!=0; ++x ) // for all faces in v1 - if(x.F()->V(0)!=v[0] && x.F()->V(1)!=v[0] && x.F()->V(2)!=v[0] ) // skip faces with v0 - on.push_back(NormalizedNormal(*x.F())); - } - - //// Move the two vertexe into new position (storing the old ones) - CoordType OldPos0=v[0]->P(); - CoordType OldPos1=v[1]->P(); - if(Params().OptimalPlacement) { v[0]->P() = ComputeMinimal(); v[1]->P()=v[0]->P();} - else v[0]->P() = v[1]->P(); - - //// Rescan faces and compute quality and difference between normals - int i; - double ndiff,MinCos = 1e100; // minimo coseno di variazione di una normale della faccia - // (e.g. max angle) Mincos varia da 1 (normali coincidenti) a - // -1 (normali opposte); - double qt, MinQual = 1e100; - CoordType nn; - for(x.F() = v[0]->VFp(), x.I() = v[0]->VFi(),i=0; x.F()!=0; ++x ) // for all faces in v0 - if(x.F()->V(0)!=v[1] && x.F()->V(1)!=v[1] && x.F()->V(2)!=v[1] ) // skip faces with v1 - { - if(Params().NormalCheck){ - nn=NormalizedNormal(*x.F()); - ndiff=nn.dot(on[i++]); - if(ndiffVFp(), x.I() = v[1]->VFi(),i=0; x.F()!=0; ++x ) // for all faces in v1 - if(x.F()->V(0)!=v[0] && x.F()->V(1)!=v[0] && x.F()->V(2)!=v[0] ) // skip faces with v0 - { - if(Params().NormalCheck){ - nn=NormalizedNormal(*x.F()); - ndiff=nn.dot(on[i++]); - if(ndiffP()); - double QuadErr = Params().ScaleFactor*qq.Apply(tpd); - - // All collapses involving triangles with quality larger than has no penalty; - if(MinQual>Params().QualityThr) MinQual=Params().QualityThr; - - if(Params().NormalCheck){ - // All collapses where the normal vary less than (e.g. more than CosineThr) - // have no penalty - if(MinCos>Params().CosineThr) MinCos=Params().CosineThr; - MinCos=(MinCos+1)/2.0; // Now it is in the range 0..1 with 0 very dangerous! - } - - if(QuadErrP()=OldPos0; - v[1]->P()=OldPos1; - this->_priority = error; - return this->_priority; - } - -// -//static double MaxError() {return 1e100;} -// - inline void UpdateHeap(HeapType & h_ret) - { - this->GlobalMark()++; - VertexType *v[2]; - v[0]= this->pos.V(0); - v[1]= this->pos.V(1); - v[1]->IMark() = this->GlobalMark(); - - // First loop around the remaining vertex to unmark visited flags - vcg::face::VFIterator vfi(v[1]); - while (!vfi.End()){ - vfi.V1()->ClearV(); - vfi.V2()->ClearV(); - ++vfi; - } - - // Second Loop - vfi = face::VFIterator(v[1]); - while (!vfi.End()) - { - assert(!vfi.F()->IsD()); - for (int j=0;j<3;j++) - { - if( !(vfi.V1()->IsV()) && vfi.V1()->IsRW()) - { - vfi.V1()->SetV(); - h_ret.push_back(HeapElem(new MYTYPE(EdgeType(vfi.V0(),vfi.V1()), this->GlobalMark()))); - std::push_heap(h_ret.begin(),h_ret.end()); - if(!IsSymmetric()){ - h_ret.push_back(HeapElem(new MYTYPE(EdgeType(vfi.V1(),vfi.V0()), this->GlobalMark()))); - std::push_heap(h_ret.begin(),h_ret.end()); - } - } - if( !(vfi.V2()->IsV()) && vfi.V2()->IsRW()) - { - vfi.V2()->SetV(); - h_ret.push_back(HeapElem(new MYTYPE(EdgeType(vfi.V0(),vfi.V2()),this->GlobalMark()))); - std::push_heap(h_ret.begin(),h_ret.end()); - if(!IsSymmetric()){ - h_ret.push_back(HeapElem(new MYTYPE(EdgeType(vfi.V2(),vfi.V0()), this->GlobalMark()))); - std::push_heap(h_ret.begin(),h_ret.end()); - } - } - if(Params().SafeHeapUpdate && vfi.V1()->IsRW() && vfi.V2()->IsRW() ) - { - h_ret.push_back(HeapElem(new MYTYPE(EdgeType(vfi.V1(),vfi.V2()),this->GlobalMark()))); - std::push_heap(h_ret.begin(),h_ret.end()); - if(!IsSymmetric()){ - h_ret.push_back(HeapElem(new MYTYPE(EdgeType(vfi.V2(),vfi.V1()), this->GlobalMark()))); - std::push_heap(h_ret.begin(),h_ret.end()); - } - } - } - ++vfi; - } - - } - -static void InitQuadric(TriMeshType &m) -{ - typename TriMeshType::FaceIterator pf; - typename TriMeshType::VertexIterator pv; - int j; - QH::Init(); - // m.ClearFlags(); - for(pv=m.vert.begin();pv!=m.vert.end();++pv) // Azzero le quadriche - if( ! (*pv).IsD() && (*pv).IsW()) - QH::Qd(*pv).SetZero(); - - - for(pf=m.face.begin();pf!=m.face.end();++pf) - if( !(*pf).IsD() && (*pf).IsR() ) - if((*pf).V(0)->IsR() &&(*pf).V(1)->IsR() &&(*pf).V(2)->IsR()) - { - QuadricType q; - Plane3 p; - // Calcolo piano - p.SetDirection( ( (*pf).V(1)->cP() - (*pf).V(0)->cP() ) ^ ( (*pf).V(2)->cP() - (*pf).V(0)->cP() )); - // Se normalizzo non dipende dall'area - - if(!Params().UseArea) - p.Normalize(); - - p.SetOffset( p.Direction().dot((*pf).V(0)->cP())); - - // Calcolo quadrica delle facce - q.ByPlane(p); - - for(j=0;j<3;++j) - if( (*pf).V(j)->IsW() ) - { - if(Params().QualityWeight) - q*=(*pf).V(j)->Q(); - QH::Qd((*pf).V(j)) += q; // Sommo la quadrica ai vertici - } - - for(j=0;j<3;++j) - if( (*pf).IsB(j) || Params().QualityQuadric ) // Bordo! - { - Plane3 pb; // Piano di bordo - - // Calcolo la normale al piano di bordo e la sua distanza - // Nota che la lunghezza dell'edge DEVE essere Normalizzata - // poiche' la pesatura in funzione dell'area e'gia fatta in p.Direction() - // Senza la normalize il bordo e' pesato in funzione della grandezza della mesh (mesh grandi non decimano sul bordo) - pb.SetDirection(p.Direction() ^ ( (*pf).V1(j)->cP() - (*pf).V(j)->cP() ).normalized()); - if( (*pf).IsB(j) ) pb.SetDirection(pb.Direction()* (ScalarType)Params().BoundaryWeight); // amplify border planes - else pb.SetDirection(pb.Direction()* (ScalarType)(Params().BoundaryWeight/100.0)); // and consider much less quadric for quality - pb.SetOffset(pb.Direction().dot((*pf).V(j)->cP())); - q.ByPlane(pb); - - if( (*pf).V (j)->IsW() ) QH::Qd((*pf).V (j)) += q; // Sommo le quadriche - if( (*pf).V1(j)->IsW() ) QH::Qd((*pf).V1(j)) += q; - } - } - - if(Params().ScaleIndependent) - { - vcg::tri::UpdateBounding::Box(m); - //Make all quadric independent from mesh size - Params().ScaleFactor = 1e8*pow(1.0/m.bbox.Diag(),6); // scaling factor - //Params().ScaleFactor *=Params().ScaleFactor ; - //Params().ScaleFactor *=Params().ScaleFactor ; - //printf("Scale factor =%f\n",Params().ScaleFactor ); - //printf("bb (%5.2f %5.2f %5.2f)-(%5.2f %5.2f %5.2f) Diag %f\n",m.bbox.min[0],m.bbox.min[1],m.bbox.min[2],m.bbox.max[0],m.bbox.max[1],m.bbox.max[2],m.bbox.Diag()); - } -} - - - -// -// -// -// -// -// -//static void InitMesh(MESH_TYPE &m){ -// Params().CosineThr=cos(Params().NormalThr); -// InitQuadric(m); -// //m.Topology(); -// //OldInitQuadric(m,UseArea); -// } -// - CoordType ComputeMinimal() -{ - typename TriMeshType::VertexType * v[2]; - v[0] = this->pos.V(0); - v[1] = this->pos.V(1); - QuadricType q=QH::Qd(v[0]); - q+=QH::Qd(v[1]); - - Point3 x; - - bool rt=q.Minimum(x); - if(!rt) { // if the computation of the minimum fails we choose between the two edge points and the middle one. - Point3 x0=Point3d::Construct(v[0]->P()); - Point3 x1=Point3d::Construct(v[1]->P()); - x.Import((v[0]->P()+v[1]->P())/2); - double qvx=q.Apply(x); - double qv0=q.Apply(x0); - double qv1=q.Apply(x1); - if(qv0 -#include -#include - -namespace vcg -{ -namespace tri -{ -/** \addtogroup trimesh */ -/* @{ */ - -/*! - * This Class is specialization of LocalModification for the edge flip - * It wraps the atomic operation EdgeFlip to be used in a optimization routine. - * Note that it has knowledge of the heap of the class LocalOptimization because - * it is responsible of updating it after a flip has been performed - * This is the simplest edge flipping class. - * It flips an edge only if two adjacent faces are coplanar and the - * quality of the faces improves after the flip. - */ -template const & p0, - Point3 const & p1, - Point3 const & p2) = Quality> -class PlanarEdgeFlip : - public LocalOptimization< TRIMESH_TYPE>::LocModType -{ -protected: - typedef typename TRIMESH_TYPE::FaceType FaceType; - typedef typename TRIMESH_TYPE::FacePointer FacePointer; - typedef typename TRIMESH_TYPE::FaceIterator FaceIterator; - typedef typename TRIMESH_TYPE::VertexType VertexType; - typedef typename TRIMESH_TYPE::ScalarType ScalarType; - typedef typename TRIMESH_TYPE::VertexPointer VertexPointer; - typedef typename TRIMESH_TYPE::CoordType CoordType; - typedef vcg::face::Pos PosType; - typedef typename LocalOptimization::HeapElem HeapElem; - typedef typename LocalOptimization::HeapType HeapType; - - /*! - * the pos of the flipping - */ - PosType _pos; - - /*! - * priority in the heap - */ - ScalarType _priority; - - /*! - * Mark for updating - */ - int _localMark; - - /*! - * mark for up_dating - */ - static int& GlobalMark() - { - static int im = 0; - return im; - } - - static void Insert(HeapType& heap, PosType& p, int mark) - { - if(!p.IsBorder() && p.F()->IsW() && p.FFlip()->IsW()) { - MYTYPE* newflip = new MYTYPE(p, mark); - heap.push_back(HeapElem(newflip)); - std::push_heap(heap.begin(), heap.end()); - } - } - -public: - /*! - * Default constructor - */ - inline PlanarEdgeFlip() - { - } - - - /*! - * Constructor with pos type - */ - inline PlanarEdgeFlip(PosType pos, int mark) - { - _pos = pos; - _localMark = mark; - _priority = this->ComputePriority(); - } - - - /*! - * Copy Constructor - */ - inline PlanarEdgeFlip(const PlanarEdgeFlip &par) - { - _pos = par.GetPos(); - _localMark = par.GetMark(); - _priority = par.Priority(); - } - - - /*! - */ - ~PlanarEdgeFlip() - { - } - - - /*! - * Parameter - */ - static ScalarType &CoplanarAngleThresholdDeg() - { - static ScalarType _CoplanarAngleThresholdDeg = 0.01f; - return _CoplanarAngleThresholdDeg; - } - - inline PosType GetPos() const - { - return _pos; - } - - inline int GetMark()const - { - return _localMark; - } - - - /*! - * Return the LocalOptimization type - */ - ModifierType IsOfType() - { - return TriEdgeFlipOp; - } - - - /*! - * Check if the pos is updated - */ - bool IsUpToDate() - { - int lastMark = _pos.F()->V(0)->IMark(); - lastMark = std::max(lastMark, _pos.F()->V(1)->IMark()); - lastMark = std::max(lastMark, _pos.F()->V(2)->IMark()); - - return ( _localMark >= lastMark ); - } - - /*! - * - Check if this flipping operation can be performed. - It is a topological and geometrical check. - */ - virtual bool IsFeasible() - { - if(!vcg::face::CheckFlipEdge(*this->_pos.F(), this->_pos.E())) - return false; - - if( math::ToDeg( Angle(_pos.FFlip()->cN(), _pos.F()->cN()) ) > CoplanarAngleThresholdDeg() ) - return false; - - CoordType v0, v1, v2, v3; - int i = _pos.E(); - - v0 = _pos.F()->P0(i); - v1 = _pos.F()->P1(i); - v2 = _pos.F()->P2(i); - v3 = _pos.F()->FFp(i)->P2(_pos.F()->FFi(i)); - - // Take the parallelogram formed by the adjacent faces of edge - // If a corner of the parallelogram on extreme of edge to flip is >= 180 - // the flip produce two identical faces - avoid this - if( (Angle(v2 - v0, v1 - v0) + Angle(v3 - v0, v1 - v0) >= M_PI) || - (Angle(v2 - v1, v0 - v1) + Angle(v3 - v1, v0 - v1) >= M_PI)) - return false; - - // if any of two faces adj to edge in non writable, the flip is unfeasible - if(!_pos.F()->IsW() || !_pos.F()->FFp(i)->IsW()) - return false; - - return true; - } - - /*! - * Compute the priority of this optimization - */ - /* - 1 - /|\ - / | \ - 2 | 3 - \ | / - \|/ - 0 - */ - ScalarType ComputePriority() - { - CoordType v0, v1, v2, v3; - int i = _pos.E(); - v0 = _pos.F()->P0(i); - v1 = _pos.F()->P1(i); - v2 = _pos.F()->P2(i); - v3 = _pos.F()->FFp(i)->P2(_pos.F()->FFi(i)); - - ScalarType Qa = QualityFunc(v0, v1, v2); - ScalarType Qb = QualityFunc(v0, v3, v1); - - ScalarType QaAfter = QualityFunc(v1, v2, v3); - ScalarType QbAfter = QualityFunc(v0, v3, v2); - - // < 0 if the average quality of faces improves after flip - _priority = (Qa + Qb - QaAfter - QbAfter) / (ScalarType)2.0; - - return _priority; - } - - /*! - * Return the priority of this optimization - */ - virtual ScalarType Priority() const - { - return _priority; - } - - /*! - * Execute the flipping of the edge - */ - void Execute(TRIMESH_TYPE &m) - { - int i = _pos.E(); - int j = _pos.F()->FFi(i); - FacePointer f1 = _pos.F(); - FacePointer f2 = _pos.F()->FFp(i); - - vcg::face::FlipEdge(*_pos.F(), _pos.E()); - - // avoid texture coordinates swap after flip - if(tri::HasPerWedgeTexCoord(m)) { - f2->WT((j + 1) % 3) = f1->WT((i + 2) % 3); - f1->WT((i + 1) % 3) = f2->WT((j + 2) % 3); - } - } - - /*! - */ - const char* Info(TRIMESH_TYPE &m) - { - static char dump[60]; - sprintf(dump,"%d -> %d %g\n", _pos.F()->V(0)-&m.vert[0], _pos.F()->V(1)-&m.vert[0],-_priority); - return dump; - } - - /*! - */ - static void Init(TRIMESH_TYPE &mesh, HeapType &heap) - { - heap.clear(); - FaceIterator fi; - for(fi = mesh.face.begin(); fi != mesh.face.end(); ++fi) { - if(!(*fi).IsD() && (*fi).IsW()) { - for(unsigned int i = 0; i < 3; i++) { - if( !(*fi).IsB(i) && !((*fi).FFp(i)->IsD()) && (*fi).FFp(i)->IsW() ) { - if((*fi).V1(i) - (*fi).V0(i) > 0) { - PosType p(&*fi, i); - Insert(heap, p, IMark(mesh)); - } - //heap.push_back( HeapElem( new MYTYPE(PosType(&*fi, i), mesh.IMark() )) ); - } //endif - } //endfor - } - } //endfor - } - - /*! - */ - virtual void UpdateHeap(HeapType &heap) - { - GlobalMark()++; - - // after flip, the new edge just created is the next edge - int flipped = (_pos.E() + 1) % 3; - - PosType pos(_pos.F(), flipped); - - pos.F()->V(0)->IMark() = GlobalMark(); - pos.F()->V(1)->IMark() = GlobalMark(); - pos.F()->V(2)->IMark() = GlobalMark(); - pos.F()->FFp(flipped)->V2(pos.F()->FFi(flipped))->IMark() = GlobalMark(); - - pos.FlipF(); pos.FlipE(); - Insert(heap, pos, GlobalMark()); - - pos.FlipV(); pos.FlipE(); - Insert(heap, pos, GlobalMark()); - - pos.FlipV(); pos.FlipE(); - pos.FlipF(); pos.FlipE(); - Insert(heap, pos, GlobalMark()); - - pos.FlipV(); pos.FlipE(); - Insert(heap, pos, GlobalMark()); - } -}; // end of PlanarEdgeFlip class - - -template -class TriEdgeFlip : public PlanarEdgeFlip -{ -protected: - typedef typename TRIMESH_TYPE::FaceType FaceType; - typedef typename TRIMESH_TYPE::ScalarType ScalarType; - typedef typename TRIMESH_TYPE::CoordType CoordType; - typedef vcg::face::Pos PosType; - -public: - /*! - * Default constructor - */ - inline TriEdgeFlip() {} - - /*! - * Constructor with pos type - */ - inline TriEdgeFlip(const PosType pos, int mark) - { - this->_pos = pos; - this->_localMark = mark; - this->_priority = ComputePriority(); - } - - /*! - * Copy Constructor - */ - inline TriEdgeFlip(const TriEdgeFlip &par) - { - this->_pos = par.GetPos(); - this->_localMark = par.GetMark(); - this->_priority = par.Priority(); - } - - - ScalarType ComputePriority() - { - /* - 1 - /|\ - / | \ - 2 | 3 - \ | / - \|/ - 0 - */ - CoordType v0, v1, v2, v3; - int i = this->_pos.E(); - v0 = this->_pos.F()->P0(i); - v1 = this->_pos.F()->P1(i); - v2 = this->_pos.F()->P2(i); - v3 = this->_pos.F()->FFp(i)->P2(this->_pos.F()->FFi(i)); - - // if the sum of angles in v2 e v3 is > 180, then the triangle - // pair is not a delaunay triangulation - ScalarType alpha = math::Abs(Angle(v0 - v2, v1 - v2)); - ScalarType beta = math::Abs(Angle(v0 - v3, v1 - v3)); - this->_priority = 180 - math::ToDeg((alpha + beta)); - return this->_priority; - } -}; - - -// This kind of flip minimize the variance of number of incident faces -// on the vertices of two faces involved in the flip -template -class TopoEdgeFlip : public PlanarEdgeFlip -{ -protected: - typedef typename TRIMESH_TYPE::VertexPointer VertexPointer; - - typedef typename TRIMESH_TYPE::FaceType FaceType; - typedef typename TRIMESH_TYPE::FacePointer FacePointer; - typedef typename TRIMESH_TYPE::ScalarType ScalarType; - typedef typename TRIMESH_TYPE::CoordType CoordType; - typedef vcg::face::Pos PosType; - - typedef typename LocalOptimization::HeapElem HeapElem; - typedef typename LocalOptimization::HeapType HeapType; - - typedef typename TRIMESH_TYPE::FaceIterator FaceIterator; - typedef typename TRIMESH_TYPE::VertexIterator VertexIterator; - -public: - /*! - * Default constructor - */ - inline TopoEdgeFlip() {} - - /*! - * Constructor with pos type - */ - inline TopoEdgeFlip(const PosType pos, int mark) - { - this->_pos = pos; - this->_localMark = mark; - this->_priority = ComputePriority(); - } - - /*! - * Copy Constructor - */ - inline TopoEdgeFlip(const TopoEdgeFlip &par) - { - this->_pos = par.GetPos(); - this->_localMark = par.GetMark(); - this->_priority = par.Priority(); - } - - - ScalarType ComputePriority() - { - /* - 1 - /|\ - / | \ - 2 | 3 - \ | / - \|/ - 0 - */ - VertexPointer v0, v1, v2, v3; - int i = this->_pos.E(); - v0 = this->_pos.F()->V0(i); - v1 = this->_pos.F()->V1(i); - v2 = this->_pos.F()->V2(i); - v3 = this->_pos.F()->FFp(i)->V2(this->_pos.F()->FFi(i)); - - // This kind of flip minimize the variance of number of incident faces - // on the vertices of two faces involved in the flip - - ScalarType avg = (v0->Q() + v1->Q() + v2->Q() + v3->Q()) / 4.0; - - ScalarType varbefore = (powf(v0->Q() - avg, 2.0) + - powf(v1->Q() - avg, 2.0) + - powf(v2->Q() - avg, 2.0) + - powf(v3->Q() - avg, 2.0)) / 4.0; - - ScalarType varafter = (powf(v0->Q() - 1 - avg, 2.0) + - powf(v1->Q() - 1 - avg, 2.0) + - powf(v2->Q() + 1 - avg, 2.0) + - powf(v3->Q() + 1 - avg, 2.0)) / 4.0; - - this->_priority = varafter - varbefore; - return this->_priority; - } - - - /*! - * Execute the flipping of the edge - */ - void Execute(TRIMESH_TYPE &m) - { - int i = this->_pos.E(); - FacePointer f1 = this->_pos.F(); - FacePointer f2 = f1->FFp(i); - int j = f1->FFi(i); - - // update the number of faces adjacent to vertices - f1->V0(i)->Q()--; - f1->V1(i)->Q()--; - f1->V2(i)->Q()++; - f2->V2(j)->Q()++; - - // do the flip - vcg::face::FlipEdge(*this->_pos.F(), this->_pos.E()); - - // avoid texture coordinates swap after flip - if (tri::HasPerWedgeTexCoord(m)) { - f2->WT((j + 1) % 3) = f1->WT((i + 2) % 3); - f1->WT((i + 1) % 3) = f2->WT((j + 2) % 3); - } - } - - - static void Init(TRIMESH_TYPE &m, HeapType &heap) - { - // reset quality field for each vertex - VertexIterator vi; - for(vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if(!(*vi).IsD()) - (*vi).Q() = 0; - - // for each vertex, put the number of incident faces in quality field - FaceIterator fi; - for(fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - for(int i = 0; i < 3; i++) - (*fi).V(i)->Q()++; - - TriEdgeFlip::Init(m, heap); - } - - - void UpdateHeap(HeapType &heap) - { - this->GlobalMark()++; - - VertexPointer v0, v1, v2, v3; - int flipped = (this->_pos.E() + 1) % 3; - FacePointer f1 = this->_pos.F(); - FacePointer f2 = this->_pos.F()->FFp(flipped); - - v0 = f1->V0(flipped); - v1 = f1->V1(flipped); - v2 = f1->V2(flipped); - v3 = f2->V2(f1->FFi(flipped)); - - v0->IMark() = this->GlobalMark(); - v1->IMark() = this->GlobalMark(); - v2->IMark() = this->GlobalMark(); - v3->IMark() = this->GlobalMark(); - - // edges of the first face, except the flipped edge - for(int i = 0; i < 3; i++) if(i != flipped) { - PosType newpos(f1, i); - Insert(heap, newpos, this->GlobalMark()); - } - - // edges of the second face, except the flipped edge - for(int i = 0; i < 3; i++) if(i != f1->FFi(flipped)) { - PosType newpos(f2, i); - Insert(heap, newpos, this->GlobalMark()); - } - - // every edge with v0, v1 v3 of f1 - for(int i = 0; i < 3; i++) { - PosType startpos(f1, i); - PosType pos(startpos); - - do { // go to the first border (if there is one) - pos.NextE(); - } while(pos != startpos && !pos.IsBorder()); - - // if a border is reached, set startpos here - if(pos.IsBorder()) - startpos = pos; - - do { - VertexPointer v = pos.VFlip(); - if(v != v0 && v != v1 && v != v2 && v != v3) - Insert(heap, pos, this->GlobalMark()); - - pos.NextE(); - } while(pos != startpos && !pos.IsBorder()); - } - - PosType startpos(f2, (f1->FFi(flipped) + 2) % 3); - PosType pos(startpos); - - do { // go to the first border (if there is one) - pos.NextE(); - } while(pos != startpos && !pos.IsBorder()); - - // if a border is reached, set startpos here - if(pos.IsBorder()) - startpos = pos; - - do { - VertexPointer v = pos.VFlip(); - if(v != v0 && v != v1 && v != v2 && v != v3) - Insert(heap, pos, this->GlobalMark()); - - pos.NextE(); - } while(pos != startpos && !pos.IsBorder()); - } -}; - - -} // end of namespace tri -} // end of namespace vcg - -#endif