From 67a80722d5bf384201ae06790132caeeb26d0d19 Mon Sep 17 00:00:00 2001 From: "T.Alderighi" Date: Fri, 4 May 2018 18:12:02 +0200 Subject: [PATCH] removed tetra complex...bootstrapping tetra in trimesh: base done foreach done Allocator done Append done quality selection topology WIP clean todo --- vcg/complex/algorithms/clean.h | 12 + vcg/complex/algorithms/update/flag.h | 47 +- vcg/complex/algorithms/update/quality.h | 20 + vcg/complex/algorithms/update/selection.h | 81 +- vcg/complex/algorithms/update/topology.h | 162 +- vcg/complex/allocate.h | 18 +- vcg/complex/append.h | 3 +- vcg/complex/base.h | 8 +- vcg/complex/foreach.h | 2 +- vcg/complex/tetrahedron/allocate.h | 2236 ----------------- vcg/complex/tetrahedron/append.h | 456 ---- vcg/complex/tetrahedron/base.h | 1065 -------- vcg/simplex/tetrahedron/component.h | 76 +- .../tetrahedron/topology.h} | 62 +- vcg/simplex/vertex/component.h | 11 +- vcg/space/tetra3.h | 39 +- wrap/io_tetramesh/export_ply.h | 2 + 17 files changed, 435 insertions(+), 3865 deletions(-) delete mode 100644 vcg/complex/tetrahedron/allocate.h delete mode 100644 vcg/complex/tetrahedron/append.h delete mode 100644 vcg/complex/tetrahedron/base.h rename vcg/{complex/tetrahedron/complex.h => simplex/tetrahedron/topology.h} (58%) diff --git a/vcg/complex/algorithms/clean.h b/vcg/complex/algorithms/clean.h index 71daded7..cea63d4c 100644 --- a/vcg/complex/algorithms/clean.h +++ b/vcg/complex/algorithms/clean.h @@ -116,6 +116,11 @@ public: typedef typename MeshType::FaceIterator FaceIterator; typedef typename MeshType::ConstFaceIterator ConstFaceIterator; typedef typename MeshType::FaceContainer FaceContainer; + typedef typename MeshType::TetraType TetraType; + typedef typename MeshType::TetraPointer TetraPointer; + typedef typename MeshType::TetraIterator TetraIterator; + typedef typename MeshType::ConstTetraIterator ConstTetraIterator; + typedef typename vcg::Box3 Box3Type; typedef GridStaticPtr TriMeshGrid; @@ -191,6 +196,13 @@ public: { (*ei).V(k) = &*mp[ (*ei).V(k) ]; } + + for (TetraIterator ti = m.tetra.begin(); ti != m.tetra.end(); ++ti) + if (!(*ti).IsD()) + for (k = 0; k < 4; ++k) + if (mp.find((typename MeshType::VertexPointer)(*ti).V(k)) != mp.end()) + (*ti).V(k) = &*mp[ (*ti).V(k) ]; + if(RemoveDegenerateFlag) RemoveDegenerateFace(m); if(RemoveDegenerateFlag && m.en>0) { RemoveDegenerateEdge(m); diff --git a/vcg/complex/algorithms/update/flag.h b/vcg/complex/algorithms/update/flag.h index 359d3256..43516012 100644 --- a/vcg/complex/algorithms/update/flag.h +++ b/vcg/complex/algorithms/update/flag.h @@ -51,6 +51,9 @@ public: typedef typename MeshType::FaceType FaceType; typedef typename MeshType::FacePointer FacePointer; typedef typename MeshType::FaceIterator FaceIterator; + typedef typename MeshType::TetraType TetraType; + typedef typename MeshType::TetraPointer TetraPointer; + typedef typename MeshType::TetraIterator TetraIterator; /// \brief Reset all the mesh flags (vertexes edge faces) setting everithing to zero (the default value for flags) @@ -65,8 +68,12 @@ public: if(HasPerFaceFlags(m) ) for(FaceIterator fi=m.face.begin(); fi!=m.face.end(); ++fi) (*fi).Flags() = 0; + if(HasPerTetraFlags(m) ) + for(TetraIterator ti=m.tetra.begin(); ti!=m.tetra.end(); ++ti) + (*ti).Flags() = 0; } + static void VertexClear(MeshType &m, unsigned int FlagMask = 0xffffffff) { RequirePerVertexFlags(m); @@ -91,6 +98,14 @@ public: if(!(*fi).IsD()) (*fi).Flags() &= andMask ; } + static void TetraClear(MeshType &m, unsigned int FlagMask = 0xffffffff) + { + RequirePerTetraFlags(m); + int andMask = ~FlagMask; + for(TetraIterator ti=m.tetra.begin(); ti!=m.tetra.end(); ++ti) + if(!(*ti).IsD()) (*ti).Flags() &= andMask ; + } + static void VertexSet(MeshType &m, unsigned int FlagMask) { RequirePerVertexFlags(m); @@ -112,6 +127,13 @@ public: if(!(*fi).IsD()) (*fi).Flags() |= FlagMask ; } + static void TetraSet(MeshType &m, unsigned int FlagMask) + { + RequirePerTetraFlags(m); + for(TetraIterator ti=m.tetra.begin(); ti!=m.tetra.end(); ++ti) + if(!(*ti).IsD()) (*ti).Flags() |= FlagMask ; + } + static void VertexClearV(MeshType &m) { VertexClear(m,VertexType::VISITED);} @@ -134,9 +156,13 @@ public: static void FaceSetV(MeshType &m) { FaceSet(m,FaceType::VISITED);} static void FaceSetB(MeshType &m) { FaceSet(m,FaceType::BORDER);} static void FaceSetF(MeshType &m) { FaceSet(m,FaceType::FAUX012);} - + static void TetraClearV(MeshType &m) { TetraClear(m, TetraType::VISITED); } + static void TetraClearS(MeshType &m) { TetraClear(m, TetraType::SELECTED); } + static void TetraClearB(MeshType &m) { TetraClear(m, TetraType::BORDER0123); } + static void TetraSetV(MeshType &m) { TetraSet(m, TetraType::VISITED); } + static void TetraSetS(MeshType &m) { TetraSet(m, TetraType::SELECTED); } + static void TetraSetB(MeshType &m) { TetraSet(m, TetraType::BORDER0123); } /// \brief Compute the border flags for the faces using the Face-Face Topology. - /** \warning Obviously it assumes that the topology has been correctly computed (see: UpdateTopology::FaceFace ) */ @@ -153,6 +179,23 @@ public: } } + /// \brief Compute the border flags for the tetras using the Tetra-Tetra Topology. + /** + \warning Obviously it assumes that the topology has been correctly computed (see: UpdateTopology::FaceFace ) +*/ + static void TetraBorderFromTT(MeshType &m) + { + RequirePerTetraFlags(m); + RequireTTAdjacency(m); + + for(TetraIterator ti=m.tetra.begin(); ti!=m.tetra.end(); ++ti) + if(!(*ti).IsD()) + for(int j = 0; j < 4; ++j) + { + if (tetrahedron::IsBorder(*fi,j)) (*ti).SetB(j); + else (*ti).ClearB(j); + } + } static void FaceBorderFromVF(MeshType &m) { diff --git a/vcg/complex/algorithms/update/quality.h b/vcg/complex/algorithms/update/quality.h index 16801750..7b8b6d2b 100644 --- a/vcg/complex/algorithms/update/quality.h +++ b/vcg/complex/algorithms/update/quality.h @@ -55,6 +55,11 @@ public: typedef typename MeshType::FaceIterator FaceIterator; typedef typename MeshType::VertexType::QualityType VertexQualityType; typedef typename MeshType::FaceType::QualityType FaceQualityType; + typedef typename MeshType::TetraType TetraType; + typedef typename MeshType::TetraPointer TetraPointer; + typedef typename MeshType::TetraIterator TetraIterator; + typedef typename MeshType::TetraType::QualityType TetraQualityType; + /** Assign to each vertex of the mesh a constant quality value. Useful for initialization. @@ -136,6 +141,21 @@ static void FaceArea(MeshType &m) (*fi).Q()=FaceQualityType(vcg::DoubleArea(*fi)/ScalarType(2.0)); } +static void TetraConstant(MeshType & m, const TetraQualityType q) +{ + tri::RequirePerTetraQuality(m); + ForEachTetra(m, [&q] (MeshType::TetraType & t) { + t.Q() = q; + }); +} +static void TetraVolume(MeshType & m) +{ + tri::RequirePerTetraQuality(m); + ForEachTetra(m, [] (MeshType::TetraType & t) { + t.Q() = TetraQualityType(vcg::Tetra::ComputeVolume(t)); + }); +} + static void VertexFromFace( MeshType &m, bool areaWeighted=true) { tri::RequirePerFaceQuality(m); diff --git a/vcg/complex/algorithms/update/selection.h b/vcg/complex/algorithms/update/selection.h index f056ec11..b7e229f5 100644 --- a/vcg/complex/algorithms/update/selection.h +++ b/vcg/complex/algorithms/update/selection.h @@ -37,6 +37,8 @@ class SelectionStack typedef typename ComputeMeshType::template PerVertexAttributeHandle< bool > vsHandle; typedef typename ComputeMeshType::template PerEdgeAttributeHandle< bool > esHandle; typedef typename ComputeMeshType::template PerFaceAttributeHandle< bool > fsHandle; + typedef typename ComputeMeshType::template PerTetraAttributeHandle< bool > tsHandle; + public: SelectionStack(ComputeMeshType &m) @@ -47,8 +49,9 @@ public: bool push() { vsHandle vsH = Allocator::template AddPerVertexAttribute< bool >(*_m); - esHandle esH = Allocator::template AddPerEdgeAttribute< bool >(*_m); + esHandle esH = Allocator::template AddPerEdgeAttribute< bool > (*_m); fsHandle fsH = Allocator::template AddPerFaceAttribute< bool > (*_m); + fsHandle tsH = Allocator::template AddPerTetraAttribute< bool > (*_m); typename ComputeMeshType::VertexIterator vi; for(vi = _m->vert.begin(); vi != _m->vert.end(); ++vi) if( !(*vi).IsD() ) vsH[*vi] = (*vi).IsS() ; @@ -61,9 +64,14 @@ public: for(fi = _m->face.begin(); fi != _m->face.end(); ++fi) if( !(*fi).IsD() ) fsH[*fi] = (*fi).IsS() ; + typename ComputeMeshType::TetraIterator ti; + for(ti = _m->tetra.begin(); ti != _m->tetra.end(); ++ti) + if( !(*ti).IsD() ) tsH[*ti] = (*ti).IsS() ; + vsV.push_back(vsH); esV.push_back(esH); fsV.push_back(fsH); + tsV.push_back(tsH); return true; } @@ -89,6 +97,8 @@ public: vsHandle vsH = vsV.back(); esHandle esH = esV.back(); fsHandle fsH = fsV.back(); + tsHandle tsH = tsV.back(); + if(! (Allocator::template IsValidHandle(*_m, vsH))) return false; for(auto vi = _m->vert.begin(); vi != _m->vert.end(); ++vi) @@ -122,12 +132,25 @@ public: } } + for (auto ti = _m->tetra.begin(); ti != _m.tetra.end(); ++ti) + if (!(*ti).IsD()) + { + if (fsH[*ti]) { + if (!andFlag) (*ti).SetS(); + } else { + if (!orFlag) (*ti).ClearS(); + } + } + Allocator::template DeletePerVertexAttribute(*_m,vsH); Allocator::template DeletePerEdgeAttribute(*_m,esH); Allocator::template DeletePerFaceAttribute(*_m,fsH); + Allocator::template DeletePerTetraAttribute(*_m,tsH); + vsV.pop_back(); esV.pop_back(); fsV.pop_back(); + tsV.pop_back(); return true; } @@ -136,6 +159,8 @@ private: std::vector vsV; std::vector esV; std::vector fsV; + std::vector tsV; + }; /// \ingroup trimesh @@ -161,6 +186,10 @@ typedef typename MeshType::EdgeIterator EdgeIterator; typedef typename MeshType::FaceType FaceType; typedef typename MeshType::FacePointer FacePointer; typedef typename MeshType::FaceIterator FaceIterator; +typedef typename MeshType::TetraType TetraType; +typedef typename MeshType::TetraPointer TetraPointer; +typedef typename MeshType::TetraIterator TetraIterator; + typedef typename vcg::Box3 Box3Type; /// \brief This function select all the vertices. @@ -186,6 +215,16 @@ static size_t FaceAll(MeshType &m) return m.fn; } +/// \brief This function select all the tetras. +static size_t TetraAll (MeshType & m) +{ + ForEachTetra(m, [] (MeshType::TetraType & t) { + t.SetS(); + }); + + return m.tn; +} + /// \brief This function clear the selection flag for all the vertices. static size_t VertexClear(MeshType &m) { @@ -210,12 +249,23 @@ static size_t FaceClear(MeshType &m) return 0; } +/// \brief This function clears the selection flag for all the tetras. +static size_t TetraClear (MeshType & m) +{ + ForEachTetra(m, [] (MeshType::TetraType & t) { + t.ClearS(); + }); + + return 0; +} + /// \brief This function clears the selection flag for all the elements of a mesh (vertices, edges, and faces). static void Clear(MeshType &m) { VertexClear(m); EdgeClear(m); FaceClear(m); + TetraClear(m); } /// \brief This function returns the number of selected faces. @@ -245,6 +295,17 @@ static size_t VertexCount(MeshType &m) return selCnt; } +/// \brief This function returns the number of selected tetras. +static size_t TetraCount (MeshType & m) +{ + size_t selCnt = 0; + ForEachTetra(m, [&selCnt] (MeshType::TetraType & t) { + if (t.IsS()) + ++selCnt; + }); + + return selCnt; +} /// \brief This function inverts the selection flag for all the faces. static size_t FaceInvert(MeshType &m) { @@ -293,6 +354,24 @@ static size_t VertexInvert(MeshType &m) return selCnt; } +/// \brief This function inverts the selection flag for all the tetras. +static size_t TetraInvert (MeshType & m) +{ + size_t selCnt = 0; + ForEachTetra(m, [&selCnt] (MeshType::TetraType & t) { + if (t.IsS()) + t.ClearS(); + else + { + t.SetS(); + ++selCnt; + } + }); + + return selCnt; +} + + /// \brief Select all the vertices that are touched by at least a single selected faces static size_t VertexFromFaceLoose(MeshType &m, bool preserveSelection=false) { diff --git a/vcg/complex/algorithms/update/topology.h b/vcg/complex/algorithms/update/topology.h index d37ddab5..2fb8bfd4 100644 --- a/vcg/complex/algorithms/update/topology.h +++ b/vcg/complex/algorithms/update/topology.h @@ -48,15 +48,97 @@ typedef typename MeshType::EdgeIterator EdgeIterator; typedef typename MeshType::FaceType FaceType; typedef typename MeshType::FacePointer FacePointer; typedef typename MeshType::FaceIterator FaceIterator; +typedef typename MeshType::TetraType TetraType; +typedef typename MeshType::TetraPointer TetraPointer; +typedef typename MeshType::TetraIterator TetraIterator; /// \headerfile topology.h vcg/complex/algorithms/update/topology.h +/// \brief Auxiliary data structure for computing tetra tetra adjacency information. +/** + * It identifies a face, storing three vertex pointers and a tetra pointer where it belongs. + */ + +class PFace +{ +public: + VertexPointer v[3]; //three ordered vertex pointers, identify a face + TetraPointer t; //the pointer to the tetra where this face belongs + int z; //index in [0..3] of the face in the tetra + bool isBorder; + + PFace () {} + PFace (TetraPointer tp, const int nz) { this->Set(tp, nz); } + + void Set (TetraPointer tp /*the tetra pointer*/, const int nz /*the face index*/) + { + assert (tp != 0); + assert (nz >= 0 && nz < 4); + + v[0] = tp->cV(Tetra::VofF(nz, 0)); + v[1] = tp->cV(Tetra::VofF(nz, 1)); + v[2] = tp->cV(Tetra::VofF(nz, 2)); + + assert(v[0] != v[1] && v[1] != v[2]); //no degenerate faces + + if (v[0] > v[1]) + std::swap(v[0], v[1]); + if (v[1] > v[2]) + std::swap(v[1], v[2]); + if (v[0] > v[1]) + std::swap(v[0], v[1]); + + t = tp; + z = nz; + + + } + + inline bool operator < (const PFace & pf) const + { + if (v[0] < pf.v[0]) + return true; + else + { + if (v[0] > pf.v[0]) return false; + + if (v[1] < pf.v[1]) + return true; + else + { + if (v[1] > pf.v[1]) return false; + + return (v[2] < pf.v[2]); + } + } + } + + inline bool operator == (const PFace & pf) const + { + return v[0] == pf.v[0] && v[1] == pf.v[1] && v[2] == pf.v[2]; + } +}; + +static void FillFaceVector (MeshType & m, std::vector & fvec) +{ + ForEachTetra(m, [&fvec] (MeshType::TetraType & t) { + for (int i = 0; i < 4; ++i) + fvec.push_back(PFace(&t, i)); + }); +} + +static void FillUniqueFaceVector (MeshType & m, std::vector & fvec) +{ + FillFaceVector(m, fvec); + std::sort(fvec.begin(), fvec.end()); + typename std::vector::iterator newEnd = std::unique(fvec.begin(), fvec.end()); +} + /// \brief Auxiliairy data structure for computing face face adjacency information. /** It identifies and edge storing two vertex pointer and a face pointer where it belong. */ - class PEdge { public: @@ -219,6 +301,60 @@ static void AllocateEdge(MeshType &m) } +/// \brief Clear the tetra-tetra topological relation, setting each involved pointer to null. +/// useful when you passed a mesh with tt adjacency to an algorithm that does not use it and chould have messed it +static void ClearTetraTetra (MeshType & m) +{ + RequireTTAdjacency(m); + ForEachTetra(m, [] (MeshType::TetraType & t) { + for (int i = 0; i < 4; ++i) + { + t.TTp(i) = NULL; + t.TTi(i) = -1; + } + }); +} + +/// \brief Updates the Tetra-Tetra topological relation by allowing to retrieve for each tetra what other tetras share their faces. +static void TetraTetra (MeshType & m) +{ + RequireTTAdjacency(m); + if (m.tn == 0) return; + + std::vector fvec; + FillFaceVector(m, fvec); + std::sort(fvec.begin(), fvec.end()); + + int nf = 0; + typename std::vector::iterator pback, pfront; + pback = fvec.begin(); + pfront = fvec.begin(); + + do + { + if (pfront == fvec.end() || !(*pfront == *pback)) + { + typename std::vector::iterator q, q_next; + for (q = pback; q < pfront - 1; ++q) + { + assert((*q).z >= 0); + q_next = q; + ++q_next; + assert((*q_next).z >= 0 && (*q_next).z < 4); + + (*q).t->TTp(q->z) = (*q_next).t; + (*q).t->TTi(q->z) = (*q_next).z; + } + + (*q).t->TTp(q->z) = pback->t; + (*q).t->TTi(q->z) = pback->z; + pback = pfront; + ++nf; + } + if (pfront == fvec.end()) break; + ++pfront; + } while (true); +} /// \brief Clear the Face-Face topological relation setting each involved pointer to null. /// useful when you passed a mesh with ff adjacency to an algorithm that does not use it and could have messed it. static void ClearFaceFace(MeshType &m) @@ -280,6 +416,30 @@ static void FaceFace(MeshType &m) } while(true); } + +/// \brief Update the vertex-tetra topological relation. +static void VertexTetra(MeshType & m) +{ + RequireVTAdjacency(m); + + + ForEachVertex(m, [] (MeshType::VertexType & v) { + v.VTp() = NULL; + v.VTi() = 0; + }); + + ForEachTetra(m, [] (MeshType::TetraType & t) { + //this works like this: the first iteration defines the end of the chain + //then it backwards chains everything + for (int i = 0; i < 4; ++i) + { + t.VTp(i) = t.V(i)->VTp(); + t.VTi(i) = t.V(i)->VTi(); + t.V(i)->VTp() = &t; + t.V(i)->VTi() = i; + } + }); +} /// \brief Update the Vertex-Face topological relation. /** The function allows to retrieve for each vertex the list of faces sharing this vertex. diff --git a/vcg/complex/allocate.h b/vcg/complex/allocate.h index 142a105b..9753c820 100644 --- a/vcg/complex/allocate.h +++ b/vcg/complex/allocate.h @@ -1131,10 +1131,10 @@ public: if(HasEFAdjacency(m)) // if (m.edge[i].cEEp(0)!=0) { - m.edge[ pu.remap[i] ].EFp(0) = m.edge[i].cEFp(0); - m.edge[ pu.remap[i] ].EFi(0) = m.edge[i].cEFi(0); - m.edge[ pu.remap[i] ].EFp(1) = m.edge[i].cEFp(1); - m.edge[ pu.remap[i] ].EFi(1) = m.edge[i].cEFi(1); + m.edge[ pu.remap[i] ].EFp() = m.edge[i].cEFp(); + m.edge[ pu.remap[i] ].EFi() = m.edge[i].cEFi(); + m.edge[ pu.remap[i] ].EFp() = m.edge[i].cEFp(); + m.edge[ pu.remap[i] ].EFi() = m.edge[i].cEFi(); } } @@ -1170,8 +1170,8 @@ public: pu.Update((*ei).VEp(i)); if(HasEEAdjacency(m)) pu.Update((*ei).EEp(i)); - if(HasEFAdjacency(m)) - pu.Update((*ei).EFp(i)); +// if(HasEFAdjacency(m)) +// pu.Update((*ei).EFp()); } } @@ -1322,7 +1322,7 @@ public: size_t pos = 0; for (size_t i = 0; i < m.tetra.size(); ++i) { - if (!m.tetra.IsD()) + if (!m.tetra[i].IsD()) { if (pos != i) { @@ -1341,7 +1341,7 @@ public: m.tetra[pos].VTi(j) = m.tetra[i].VTi(j); } else - m.tetra[pos].VTClear(); + m.tetra[pos].VTClear(j); } //import TT adj if (HasTTAdjacency(m)) @@ -1397,7 +1397,7 @@ public: for (int i = 0; i < 4; ++i) if ((*ti).IsVTInitialized(i) && (*ti).VTp(i) != 0) { - size_t oldIndex = (*ti).VTp(i) - fbase; + size_t oldIndex = (*ti).VTp(i) - tbase; assert(tbase <= (*ti).VTp(i) && oldIndex < pu.remap.size()); (*ti).VTp(i) = tbase + pu.remap[oldIndex]; } diff --git a/vcg/complex/append.h b/vcg/complex/append.h index 484ed9cb..a127509b 100644 --- a/vcg/complex/append.h +++ b/vcg/complex/append.h @@ -193,7 +193,6 @@ public: { // Tetra to Tetra Adj if(HasTTAdjacency(ml) && HasTTAdjacency(mr)){ - assert(tl.TN() == tr.TN()); for( int vi = 0; vi < 4; ++vi ){ size_t idx = remap.tetra[Index(mr,tr.cTTp(vi))]; if(idx != Remap::InvalidIndex()){ @@ -307,7 +306,7 @@ static void Mesh(MeshLeft& ml, ConstMeshRight& mr, const bool selected = false, for (TetraIteratorRight ti = mr.tetra.begin(); ti != mr.tetra.end(); ++ti) if (!(*ti).IsD() && (!selected || (*ti).IsS())) { size_t idx = Index(mr, *ti); - assert (remap.tetra[ind] == Remap::InvalidIndex()); + assert (remap.tetra[idx] == Remap::InvalidIndex()); TetraIteratorLeft tp = Allocator::AddTetras(ml, 1); (*tp).ImportData(*ti); remap.tetra[idx] = Index(ml, *tp); diff --git a/vcg/complex/base.h b/vcg/complex/base.h index 074bac0c..a73b9eb7 100644 --- a/vcg/complex/base.h +++ b/vcg/complex/base.h @@ -641,10 +641,10 @@ template < class TetraType> bool TetraVectorHasPerTetraQuality(const std::vector template < class TetraType> bool TetraVectorHasVTAdjacency (const std::vector &) { return TetraType::HasVTAdjacency(); } template < class TetraType> bool TetraVectorHasTTAdjacency (const std::vector &) { return TetraType::HasTTAdjacency(); } -template < class TriMeshType> bool HasPerTetraFlags (const TriMeshType &m) { return tri::FaceVectorHasPerTetraFlags (m.face); } -template < class TriMeshType> bool HasPerTetraColor (const TriMeshType &m) { return tri::FaceVectorHasPerTetraColor (m.face); } -template < class TriMeshType> bool HasPerTetraMark (const TriMeshType &m) { return tri::FaceVectorHasPerTetraMark (m.face); } -template < class TriMeshType> bool HasPerTetraQuality (const TriMeshType &m) { return tri::FaceVectorHasPerTetraQuality (m.face); } +template < class TriMeshType> bool HasPerTetraFlags (const TriMeshType &m) { return tri::TetraVectorHasPerTetraFlags (m.tetra); } +template < class TriMeshType> bool HasPerTetraColor (const TriMeshType &m) { return tri::TetraVectorHasPerTetraColor (m.tetra); } +template < class TriMeshType> bool HasPerTetraMark (const TriMeshType &m) { return tri::TetraVectorHasPerTetraMark (m.tetra); } +template < class TriMeshType> bool HasPerTetraQuality (const TriMeshType &m) { return tri::TetraVectorHasPerTetraQuality (m.tetra); } template < class TriMeshType> bool HasFFAdjacency (const TriMeshType &m) { return tri::FaceVectorHasFFAdjacency (m.face); } template < class TriMeshType> bool HasEEAdjacency (const TriMeshType &m) { return tri::EdgeVectorHasEEAdjacency (m.edge); } diff --git a/vcg/complex/foreach.h b/vcg/complex/foreach.h index aa94b4f4..ae36cabd 100644 --- a/vcg/complex/foreach.h +++ b/vcg/complex/foreach.h @@ -190,7 +190,7 @@ inline void ForEachTetra(MeshType &m, std::function -size_t Index(MeshType &m, const typename MeshType::VertexType &v) { return &v - &*m.vert.begin(); } -template -size_t Index(MeshType &m, const typename MeshType::FaceType &f) { return &f - &*m.face.begin(); } -template -size_t Index(MeshType &m, const typename MeshType::EdgeType &e) { return &e - &*m.edge.begin(); } -template -size_t Index(MeshType &m, const typename MeshType::TetraType &t) { return &t - &*m.tetra.begin(); } - -template -size_t Index(MeshType &m, const typename MeshType::VertexType *vp) { return vp - &*m.vert.begin(); } -template -size_t Index(MeshType &m, const typename MeshType::FaceType *fp) { return fp - &*m.face.begin(); } -template -size_t Index(MeshType &m, const typename MeshType::EdgeType *e) { return e - &*m.edge.begin(); } -template -size_t Index(MeshType &m, const typename MeshType::TetraType *t) { return t - &*m.tetra.begin(); } - -template -bool IsValidPointer(MeshType &m, const typename MeshType::VertexType *vp) { return (m.vert.size() > 0 && (vp >= &*m.vert.begin()) && (vp <= &m.vert.back())); } -template -bool IsValidPointer(MeshType &m, const typename MeshType::EdgeType *ep) { return (m.edge.size() > 0 && (ep >= &*m.edge.begin()) && (ep <= &m.edge.back())); } -template -bool IsValidPointer(MeshType &m, const typename MeshType::FaceType *fp) { return (m.face.size() > 0 && (fp >= &*m.face.begin()) && (fp <= &m.face.back())); } -template -bool IsValidPointer(MeshType &m, const typename MeshType::TetraType *tp) { return (m.tetra.size() > 0 && (tp >= &*m.tetra.begin()) && (tp <= &m.tetra.back())); } - -template -void ReorderAttribute(ATTR_CONT &c, std::vector &newVertIndex, MeshType & /* m */) -{ - typename std::set::iterator ai; - for (ai = c.begin(); ai != c.end(); ++ai) - ((typename MeshType::PointerToAttribute)(*ai)).Reorder(newVertIndex); -} - -template -void ResizeAttribute(ATTR_CONT &c, size_t sz, MeshType & /*m*/) -{ - typename std::set::iterator ai; - for (ai = c.begin(); ai != c.end(); ++ai) - ((typename MeshType::PointerToAttribute)(*ai)).Resize(sz); -} - -/*! - \brief Class to safely add and delete elements in a mesh. - - Adding elements to a mesh, like faces and vertices can involve the reallocation of the vectors of the involved elements. - This class provide the only safe methods to add elements. - It also provide an accessory class vcg::tri::PointerUpdater for updating pointers to mesh elements that are kept by the user. - */ -template -class Allocator -{ - -public: - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::VertContainer VertContainer; - - typedef typename MeshType::EdgeType EdgeType; - typedef typename MeshType::EdgePointer EdgePointer; - typedef typename MeshType::EdgeIterator EdgeIterator; - typedef typename MeshType::EdgeContainer EdgeContainer; - - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::FacePointer FacePointer; - typedef typename MeshType::FaceIterator FaceIterator; - typedef typename MeshType::FaceContainer FaceContainer; - - typedef typename MeshType::TetraType TetraType; - typedef typename MeshType::TetraPointer TetraPointer; - typedef typename MeshType::TetraIterator TetraIterator; - typedef typename MeshType::TetraContainer TetraContainer; - - typedef typename MeshType::CoordType CoordType; - - typedef typename MeshType::PointerToAttribute PointerToAttribute; - typedef typename std::set::iterator AttrIterator; - typedef typename std::set::const_iterator AttrConstIterator; - typedef typename std::set::iterator PAIte; - - /*! - \brief Accessory class to update pointers after eventual reallocation caused by adding elements. - - This class is used whenever you trigger some allocation operation that can cause the invalidation of the pointers to mesh elements. - Typical situations are when you are allocating new vertexes, edges, halfedges of faces or when you compact - their containers to get rid of deleted elements. - This object allows you to update an invalidate pointer immediately after an action that invalidate it. - \note It can also be used to prevent any update of the various internal pointers caused by an invalidation. - This can be useful in case you are building all the internal connections by hand as it happens in a importer; - \sa \ref allocation - */ - template - class PointerUpdater - { - public: - PointerUpdater(void) : newBase(0), oldBase(0), newEnd(0), oldEnd(0), preventUpdateFlag(false) { ; } - void Clear() - { - newBase = oldBase = newEnd = oldEnd = 0; - remap.clear(); - } - /*! \brief Update a pointer to an element of a mesh after a reallocation - - The updating is correctly done only if this PointerUpdater have been passed to the corresponing allocation call. \sa \ref allocation - */ - void Update(SimplexPointerType &vp) - { - //if(vp>=newBase && vp oldEnd) - return; - assert(vp >= oldBase); - assert(vp < oldEnd); - vp = newBase + (vp - oldBase); - if (!remap.empty()) - vp = newBase + remap[vp - newBase]; - } - /*! - \brief return true if the allocation operation that initialized this PointerUpdater has caused a reallocation - */ - bool NeedUpdate() - { - if ((oldBase && newBase != oldBase && !preventUpdateFlag) || !remap.empty()) - return true; - else - return false; - } - - SimplexPointerType newBase; - SimplexPointerType oldBase; - SimplexPointerType newEnd; - SimplexPointerType oldEnd; - std::vector remap; // this vector keep the new position of an element. Uninitialized elements have max_int value to denote an element that has not to be remapped. - - bool preventUpdateFlag; /// when true no update is considered necessary. - }; - - /* +++++++++++++++ Add Vertices ++++++++++++++++ */ - - /** \brief Add n vertices to the mesh. - Function to add n vertices to the mesh. - The elements are added always to the end of the vector. - No attempt of reusing previously deleted element is done. - \sa PointerUpdater - \param m the mesh to be modified - \param n the number of elements to be added - \param pu a PointerUpdater initialized so that it can be used to update pointers to vertices that could have become invalid after this adding. - \retval the iterator to the first element added. - */ - static VertexIterator AddVertices(MeshType &m, size_t n, PointerUpdater &pu) - { - VertexIterator last; - if (n == 0) - return m.vert.end(); - pu.Clear(); - if (m.vert.empty()) - pu.oldBase = 0; // if the vector is empty we cannot find the last valid element - else - { - pu.oldBase = &*m.vert.begin(); - pu.oldEnd = &m.vert.back() + 1; - } - - m.vert.resize(m.vert.size() + n); - m.vn += int(n); - - typename std::set::iterator ai; - for (ai = m.vert_attr.begin(); ai != m.vert_attr.end(); ++ai) - ((PointerToAttribute)(*ai)).Resize(m.vert.size()); - - pu.newBase = &*m.vert.begin(); - pu.newEnd = &m.vert.back() + 1; - if (pu.NeedUpdate()) - { - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if (!(*fi).IsD()) - for (int i = 0; i < (*fi).VN(); ++i) - if ((*fi).cV(i) != 0) - pu.Update((*fi).V(i)); - - for (EdgeIterator ei = m.edge.begin(); ei != m.edge.end(); ++ei) - if (!(*ei).IsD()) - { - pu.Update((*ei).V(0)); - pu.Update((*ei).V(1)); - // if(HasEVAdjacency(m)) - } - - for (TetraIterator ti = m.tetra.begin(); ti != m.tetra.end(); ++ti) - if (!(*ti).IsD()) - for (int i = 0; i < 4; ++i) - if ((*ti).cV(i) != 0) - pu.Update((*ti).V(i)); - // HEdgeIterator hi; - // for (hi=m.hedge.begin(); hi!=m.hedge.end(); ++hi) - // if(!(*hi).IsD()) - // { - // if(HasHVAdjacency (m)) - // { - // pu.Update((*hi).HVp()); - // } - // } - - // e poiche' lo spazio e' cambiato si ricalcola anche last da zero - } - size_t siz = (size_t)(m.vert.size() - n); - - last = m.vert.begin(); - advance(last, siz); - - return last; // deve restituire l'iteratore alla prima faccia aggiunta; - } - - /** \brief Wrapper to AddVertices(); no PointerUpdater - */ - static VertexIterator AddVertices(MeshType &m, size_t n) - { - PointerUpdater pu; - return AddVertices(m, n, pu); - } - - /** \brief Wrapper to AddVertices() no PointerUpdater but a vector of VertexPointer pointers to be updated - */ - static VertexIterator AddVertices(MeshType &m, size_t n, std::vector &local_vec) - { - PointerUpdater pu; - VertexIterator v_ret = AddVertices(m, n, pu); - - typename std::vector::iterator vi; - for (vi = local_vec.begin(); vi != local_vec.end(); ++vi) - pu.Update(**vi); - return v_ret; - } - - /** \brief Wrapper to AddVertices() to add a single vertex with given coords - */ - static VertexIterator AddVertex(MeshType &m, const CoordType &p) - { - VertexIterator v_ret = AddVertices(m, 1); - v_ret->P() = p; - return v_ret; - } - - /** \brief Wrapper to AddVertices() to add a single vertex with given coords and normal - */ - static VertexIterator AddVertex(MeshType &m, const CoordType &p, const CoordType &n) - { - VertexIterator v_ret = AddVertices(m, 1); - v_ret->P() = p; - v_ret->N() = n; - return v_ret; - } - - /** \brief Wrapper to AddVertices() to add a single vertex with given coords and color - */ - static VertexIterator AddVertex(MeshType &m, const CoordType &p, const Color4b &c) - { - VertexIterator v_ret = AddVertices(m, 1); - v_ret->P() = p; - v_ret->C() = c; - return v_ret; - } - - /* +++++++++++++++ Add Edges ++++++++++++++++ */ - - /** \brief Add n edges to the mesh. - Function to add n edges to the mesh. - The elements are added always to the end of the vector. No attempt of reusing previously deleted element is done. - \sa PointerUpdater - \param m the mesh to be modified - \param n the number of elements to be added - \param pu a PointerUpdater initialized so that it can be used to update pointers to edges that could have become invalid after this adding. - \retval the iterator to the first element added. - */ - static EdgeIterator AddEdges(MeshType &m, size_t n, PointerUpdater &pu) - { - if (n == 0) - return m.edge.end(); - pu.Clear(); - if (m.edge.empty()) - pu.oldBase = 0; // if the vector is empty we cannot find the last valid element - else - { - pu.oldBase = &*m.edge.begin(); - pu.oldEnd = &m.edge.back() + 1; - } - - m.edge.resize(m.edge.size() + n); - m.en += int(n); - size_t siz = (size_t)(m.edge.size() - n); - EdgeIterator firstNewEdge = m.edge.begin(); - advance(firstNewEdge, siz); - - typename std::set::iterator ai; - for (ai = m.edge_attr.begin(); ai != m.edge_attr.end(); ++ai) - ((typename MeshType::PointerToAttribute)(*ai)).Resize(m.edge.size()); - - pu.newBase = &*m.edge.begin(); - pu.newEnd = &m.edge.back() + 1; - if (pu.NeedUpdate()) - { - if (HasFEAdjacency(m)) - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - { - if (!(*fi).IsD()) - for (int i = 0; i < (*fi).VN(); ++i) - if ((*fi).cFEp(i) != 0) - pu.Update((*fi).FEp(i)); - } - - if (HasVEAdjacency(m)) - { - for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if (!(*vi).IsD()) - if ((*vi).cVEp() != 0) - pu.Update((*vi).VEp()); - for (EdgeIterator ei = m.edge.begin(); ei != firstNewEdge; ++ei) - if (!(*ei).IsD()) - { - if ((*ei).cVEp(0) != 0) - pu.Update((*ei).VEp(0)); - if ((*ei).cVEp(1) != 0) - pu.Update((*ei).VEp(1)); - } - } - - //if(HasTEAdjacency(m)) - //.... - - // if(HasHEAdjacency(m)) - // for (HEdgeIterator hi=m.hedge.begin(); hi!=m.hedge.end(); ++hi) - // if(!(*hi).IsD()) - // if ((*hi).cHEp()!=0) pu.Update((*hi).HEp()); - } - - return firstNewEdge; // deve restituire l'iteratore alla prima faccia aggiunta; - } - - /** Function to add a single edge to the mesh. and initializing it with two VertexPointer - */ - static EdgeIterator AddEdge(MeshType &m, VertexPointer v0, VertexPointer v1) - { - EdgeIterator ei = AddEdges(m, 1); - ei->V(0) = v0; - ei->V(1) = v1; - return ei; - } - - /** Function to add a single edge to the mesh. and initializing it with two indexes to the vertexes - */ - static EdgeIterator AddEdge(MeshType &m, size_t v0, size_t v1) - { - assert(v0 != v1); - assert(v0 >= 0 && v0 < m.vert.size()); - assert(v1 >= 0 && v1 < m.vert.size()); - return AddEdge(m, &(m.vert[v0]), &(m.vert[v1])); - } - - /** Function to add a face to the mesh and initializing it with the three given coords - */ - static EdgeIterator AddEdge(MeshType &m, CoordType p0, CoordType p1) - { - VertexIterator vi = AddVertices(m, 2); - EdgeIterator ei = AddEdges(m, 1); - vi->P() = p0; - ei->V(0) = &*vi++; - vi->P() = p1; - ei->V(1) = &*vi++; - return ei; - } - - /** Function to add n edges to the mesh. - First wrapper, with no parameters - */ - static EdgeIterator AddEdges(MeshType &m, size_t n) - { - PointerUpdater pu; - return AddEdges(m, n, pu); - } - - /** Function to add n edges to the mesh. - Second Wrapper, with a vector of vertex pointers to be updated. - */ - static EdgeIterator AddEdges(MeshType &m, size_t n, std::vector &local_vec) - { - PointerUpdater pu; - EdgeIterator v_ret = AddEdges(m, n, pu); - - typename std::vector::iterator ei; - for (ei = local_vec.begin(); ei != local_vec.end(); ++ei) - pu.Update(**ei); - return v_ret; - } - - /* +++++++++++++++ Add HalfEdges ++++++++++++++++ */ - - // /** Function to add n halfedges to the mesh. The second parameter hold a vector of - // pointers to pointer to elements of the mesh that should be updated after a - // possible vector realloc. - // \sa PointerUpdater - // \param m the mesh to be modified - // \param n the number of elements to be added - // \param pu a PointerUpdater initialized so that it can be used to update pointers to edges that could have become invalid after this adding. - // \retval the iterator to the first element added. - // */ - // static HEdgeIterator AddHEdges(MeshType &m, size_t n, PointerUpdater &pu) - // { - // HEdgeIterator last; - // if(n == 0) return m.hedge.end(); - // pu.Clear(); - // if(m.hedge.empty()) pu.oldBase=0; // if the vector is empty we cannot find the last valid element - // else { - // pu.oldBase=&*m.hedge.begin(); - // pu.oldEnd=&m.hedge.back()+1; - // } - - // m.hedge.resize(m.hedge.size()+n); - // m.hn+=int(n); - - // pu.newBase = &*m.hedge.begin(); - // pu.newEnd = &m.hedge.back()+1; - - // if(pu.NeedUpdate()) - // { - // if(HasFHAdjacency(m)) { - // for (FaceIterator fi=m.face.begin(); fi!=m.face.end(); ++fi) - // { - // if(!(*fi).IsD() && (*fi).FHp()) - // pu.Update((*fi).FHp()); - // } - // } - // if(HasVHAdjacency(m)) { - // for (VertexIterator vi=m.vert.begin(); vi!=m.vert.end(); ++vi) - // if(!(*vi).IsD() && (*vi).cVHp()!=0) - // pu.Update((*vi).VHp()); - // } - // if(HasEHAdjacency(m)) { - // for (EdgeIterator ei=m.edge.begin(); ei!=m.edge.end(); ++ei) - // if(!(*ei).IsD() && (*ei).cEHp()!=0) - // pu.Update((*ei).EHp()); - // } - - // int ii = 0; - // HEdgeIterator hi = m.hedge.begin(); - // while(ii < m.hn - int(n))// cycle on all the faces except the new ones - // { - // if(!(*hi).IsD()) - // { - // if(HasHNextAdjacency(m)) pu.Update((*hi).HNp()); - // if(HasHPrevAdjacency(m)) pu.Update((*hi).HPp()); - // if(HasHOppAdjacency(m)) pu.Update((*hi).HOp()); - // ++ii; - // } - // ++hi; - // } - // } - // size_t siz = (size_t)(m.hedge.size()-n); - - // last = m.hedge.begin(); - // advance(last,siz); - - // return last;// deve restituire l'iteratore alla prima faccia aggiunta; - // } - - // /** Function to add n vertices to the mesh. - // First wrapper, with no parameters - // */ - // static HEdgeIterator AddHEdges(MeshType &m, size_t n) - // { - // PointerUpdater pu; - // return AddHEdges(m, n,pu); - // } - - // /** Function to add n vertices to the mesh. - // Second Wrapper, with a vector of vertex pointers to be updated. - // */ - // static HEdgeIterator AddHEdges(MeshType &m, size_t n, std::vector &local_vec) - // { - // PointerUpdater pu; - // HEdgeIterator v_ret = AddHEdges(m, n,pu); - - // typename std::vector::iterator ei; - // for(ei=local_vec.begin();ei!=local_vec.end();++ei) - // pu.Update(**ei); - // return v_ret; - // } - - /* +++++++++++++++ Add Faces ++++++++++++++++ */ - - /** Function to add a face to the mesh and initializing it with the three given VertexPointers - */ - static FaceIterator AddFace(MeshType &m, VertexPointer v0, VertexPointer v1, VertexPointer v2) - { - assert(m.vert.size() > 0); - assert((v0 != v1) && (v1 != v2) && (v0 != v2)); - assert(v0 >= &m.vert.front() && v0 <= &m.vert.back()); - assert(v1 >= &m.vert.front() && v1 <= &m.vert.back()); - assert(v2 >= &m.vert.front() && v2 <= &m.vert.back()); - PointerUpdater pu; - FaceIterator fi = AddFaces(m, 1, pu); - fi->Alloc(3); - fi->V(0) = v0; - fi->V(1) = v1; - fi->V(2) = v2; - return fi; - } - - /** Function to add a face to the mesh and initializing it with three indexes - */ - static FaceIterator AddFace(MeshType &m, size_t v0, size_t v1, size_t v2) - { - assert((v0 != v1) && (v1 != v2) && (v0 != v2)); - assert(v0 >= 0 && v0 < m.vert.size()); - assert(v1 >= 0 && v1 < m.vert.size()); - assert(v2 >= 0 && v2 < m.vert.size()); - return AddFace(m, &(m.vert[v0]), &(m.vert[v1]), &(m.vert[v2])); - } - /** Function to add a face to the mesh and initializing it with the three given coords - */ - static FaceIterator AddFace(MeshType &m, CoordType p0, CoordType p1, CoordType p2) - { - VertexIterator vi = AddVertices(m, 3); - FaceIterator fi = AddFaces(m, 1); - fi->Alloc(3); - vi->P() = p0; - fi->V(0) = &*vi++; - vi->P() = p1; - fi->V(1) = &*vi++; - vi->P() = p2; - fi->V(2) = &*vi; - return fi; - } - - /** \brief Function to add n faces to the mesh. - First wrapper, with no parameters - */ - static FaceIterator AddFaces(MeshType &m, size_t n) - { - PointerUpdater pu; - return AddFaces(m, n, pu); - } - - /** \brief Function to add n faces to the mesh. - Second Wrapper, with a vector of face pointer to be updated. - */ - static FaceIterator AddFaces(MeshType &m, size_t n, std::vector &local_vec) - { - PointerUpdater pu; - FaceIterator f_ret = AddFaces(m, n, pu); - - typename std::vector::iterator fi; - for (fi = local_vec.begin(); fi != local_vec.end(); ++fi) - pu.Update(**fi); - return f_ret; - } - - /** \brief Function to add n faces to the mesh. - This is the only full featured function that is able to manage correctly - all the official internal pointers of the mesh (like the VF and FF adjacency relations) - \warning Calling this function can cause the invalidation of any not-managed FacePointer - just because we resize the face vector. - If you have such pointers you need to update them by mean of the PointerUpdater object. - \sa PointerUpdater - \param m the mesh to be modified - \param n the number of elements to be added - \param pu a PointerUpdater initialized so that it can be used to update pointers to edges that could have become invalid after this adding. - \retval the iterator to the first element added. - */ - static FaceIterator AddFaces(MeshType &m, size_t n, PointerUpdater &pu) - { - pu.Clear(); - if (n == 0) - return m.face.end(); - if (!m.face.empty()) // if the vector is empty we cannot find the last valid element - { - pu.oldBase = &*m.face.begin(); - pu.oldEnd = &m.face.back() + 1; - } - // The actual resize - m.face.resize(m.face.size() + n); - m.fn += int(n); - - size_t siz = (size_t)(m.face.size() - n); - FaceIterator firstNewFace = m.face.begin(); - advance(firstNewFace, siz); - - typename std::set::iterator ai; - for (ai = m.face_attr.begin(); ai != m.face_attr.end(); ++ai) - ((PointerToAttribute)(*ai)).Resize(m.face.size()); - - pu.newBase = &*m.face.begin(); - pu.newEnd = &m.face.back() + 1; - - if (pu.NeedUpdate()) - { - if (HasFFAdjacency(m)) - { // cycle on all the faces except the new ones - for (FaceIterator fi = m.face.begin(); fi != firstNewFace; ++fi) - if (!(*fi).IsD()) - for (int i = 0; i < (*fi).VN(); ++i) - if ((*fi).cFFp(i) != 0) - pu.Update((*fi).FFp(i)); - } - - if (HasPerVertexVFAdjacency(m) && HasPerFaceVFAdjacency(m)) - { // cycle on all the faces except the new ones - for (FaceIterator fi = m.face.begin(); fi != firstNewFace; ++fi) - if (!(*fi).IsD()) - for (int i = 0; i < (*fi).VN(); ++i) - if ((*fi).cVFp(i) != 0) - pu.Update((*fi).VFp(i)); - - for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if (!(*vi).IsD() && (*vi).cVFp() != 0) - pu.Update((*vi).VFp()); - } - - if (HasEFAdjacency(m)) - { - for (EdgeIterator ei = m.edge.begin(); ei != m.edge.end(); ++ei) - if (!(*ei).IsD() && (*ei).cEFp() != 0) - pu.Update((*ei).EFp()); - } - -// if (HasHFAdjacency(m)) -// { -// for (HEdgeIterator hi = m.hedge.begin(); hi != m.hedge.end(); ++hi) -// if (!(*hi).IsD() && (*hi).cHFp() != 0) -// pu.Update((*hi).HFp()); -// } - } - return firstNewFace; - } - - //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - //:::::::::::::::::TETRAS ADDER FUNCTIONS::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - //do all the other adder funcitons - - /** \brief Function to add n tetras to the mesh. - This is the only full featured function that is able to manage correctly - all the official internal pointers of the mesh (like the VT and TT adjacency relations) - \warning Calling this function can cause the invalidation of any not-managed TetraPointer - just because we resize the face vector. - If you have such pointers you need to update them by mean of the PointerUpdater object. - \sa PointerUpdater - \param m the mesh to be modified - \param n the number of elements to be added - \param pu a PointerUpdater initialized so that it can be used to update pointers to tetras that could have become invalid after this adding. - \retval the iterator to the first element added. - */ - static TetraIterator AddTetras(MeshType &m, size_t n, PointerUpdater &pu) - { - //nothing to do - if (n == 0) - return m.tetra.end(); - - //prepare the pointerupdater info - pu.Clear(); - if (m.tetra.empty()) - pu.oldBase = 0; - else - { - pu.oldBase = &*m.tetra.begin(); - pu.oldEnd = &m.tetra.back() + 1; - } - - //resize the tetra list and update tetra count - m.tetra.resize(m.tetra.size() + n); - m.tn += n; - - //get the old size and advance to the first new tetrahedron position - size_t oldSize = (size_t)(m.tetra.size() - n); - - TetraIterator firstNewTetra = m.tetra.begin(); - advance(firstNewTetra, oldSize); - - //for each attribute make adapt the list size - typename std::set::iterator ai; - for (ai = m.tetra_attr.begin(); ai != m.tetra_attr.end(); ++ai) - ((typename MeshType::PointerToAttribute)(*ai)).Resize(m.tetra.size()); - - //do the update - pu.newBase = &*m.tetra.begin(); - pu.newEnd = &m.tetra.back() + 1; - if (pu.NeedUpdate()) - { - if (HasVTAdjacency(m)) - { - for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if (!vi->IsD()) - pu.Update(vi->VTp()); - - for (TetraIterator ti = m.tetra.begin(); ti != m.tetra.end(); ++ti) - if (!ti->IsD()) - { - pu.Update(ti->VTp(0)); - pu.Update(ti->VTp(1)); - pu.Update(ti->VTp(2)); - pu.Update(ti->VTp(3)); - } - } - - //do edge and face adjacency - if (HasTTAdjacency(m)) - for (TetraIterator ti = m.tetra.begin(); ti != m.tetra.end(); ++ti) - if (!ti->IsD()) - { - pu.Update(ti->TTp(0)); - pu.Update(ti->TTp(1)); - pu.Update(ti->TTp(2)); - pu.Update(ti->TTp(3)); - } - } - - return firstNewTetra; - } - -//TODO: ADD 4 FACES then add tetra - /** Function to add a face to the mesh and initializing it with the three given VertexPointers - */ - static TetraIterator AddTetra(MeshType &m, VertexPointer v0, VertexPointer v1, VertexPointer v2, VertexPointer v3) - { - assert(m.vert.size() > 0); - assert((v0 != v1) && (v0 != v2) && (v0 != v3) && (v1 != v2) && (v1 != v3) && (v2 != v3)); - assert(v0 >= &m.vert.front() && v0 <= &m.vert.back()); - assert(v1 >= &m.vert.front() && v1 <= &m.vert.back()); - assert(v2 >= &m.vert.front() && v2 <= &m.vert.back()); - assert(v3 >= &m.vert.front() && v3 <= &m.vert.back()); - - AddFace(m, v0, v1, v2); - AddFace(m, v0, v3, v1); - AddFace(m, v0, v2, v3); - AddFace(m, v1, v3, v2); - - PointerUpdater pu; - TetraIterator ti = AddTetras(m, 1, pu); - ti->V(0) = v0; - ti->V(1) = v1; - ti->V(2) = v2; - ti->V(3) = v3; - return ti; - } - - /** Function to add a face to the mesh and initializing it with three indexes - */ - static TetraIterator AddTetra(MeshType &m, const size_t v0, const size_t v1, const size_t v2, const size_t v3) - { - assert(m.vert.size() > 0); - assert((v0 != v1) && (v0 != v2) && (v0 != v3) && (v1 != v2) && (v1 != v3) && (v2 != v3)); - assert(v0 >= 0 && v0 < m.vert.size()); - assert(v1 >= 0 && v1 < m.vert.size()); - assert(v2 >= 0 && v2 < m.vert.size()); - assert(v3 >= 0 && v3 < m.vert.size()); - - return AddTetra(m, &(m.vert[v0]), &(m.vert[v1]), &(m.vert[v2]), &(m.vert[v3])); - } - /** Function to add a face to the mesh and initializing it with the three given coords - */ - static TetraIterator AddTetra(MeshType &m, const CoordType & p0, const CoordType & p1, const CoordType & p2, const CoordType & p3) - { - VertexIterator vi = AddVertices(m, 4); - - VertexPointer v0 = &*vi++; - VertexPointer v1 = &*vi++; - VertexPointer v2 = &*vi++; - VertexPointer v3 = &*vi++; - - v0->P() = p0; - v1->P() = p1; - v2->P() = p2; - v3->P() = p3; - - return AddTetra(m, v0, v1, v2, v3); - } - -//requires no duplicate vertices on faces you use - static TetraIterator AddTetra(MeshType &m, const FaceType & f0, const FaceType & f1, const FaceType & f2, const FaceType & f3) - { - assert(m.face.size() > 0); - assert((f0 != f1) && (f0 != f2) && (f0 != f3) && (f1 != f2) && (f1 != f3) && (f2 != f3)); - assert(f1 >= 0 && f1 < m.face.size()); - assert(f2 >= 0 && f2 < m.face.size()); - assert(f3 >= 0 && f3 < m.face.size()); - assert(f0 >= 0 && f0 < m.face.size()); - //TODO: decide if you want to address this like this - //ERROR: can't use position...so..could force to have no dup verts..and use pointers or avoid this kind of thing - assert(f0.V(0) == f1.V(0) && f0.V(0) == f2.V(0) && //v0 - f0.V(1) == f1.V(2) && f0.V(1) == f3.V(0) && //v1 - f0.V(2) == f2.V(1) && f0.V(2) == f3.V(2) && //v2 - f1.V(1) == f2.V(2) && f1.V(1) == f3.V(1) ) //v3 - - //add a tetra...and set vertices correctly - PointerUpdater pu; - TetraIterator ti = AddTetras(m, 1, pu); - ti->V(0) = f0.V(0); - ti->V(1) = f0.V(1); - ti->V(2) = f0.V(2); - ti->V(3) = f1.V(1); - - return ti; - } - - /** \brief Function to add n faces to the mesh. - First wrapper, with no parameters - */ - static TetraIterator AddTetras(MeshType &m, size_t n) - { - PointerUpdater pu; - return AddTetras(m, n, pu); - } - - /** \brief Function to add n faces to the mesh. - Second Wrapper, with a vector of face pointer to be updated. - */ - static TetraIterator AddTetras(MeshType &m, size_t n, std::vector &local_vec) - { - PointerUpdater pu; - TetraIterator t_ret = AddTetras(m, n, pu); - - typename std::vector::iterator fi; - for (ti = local_vec.begin(); ti != local_vec.end(); ++ti) - pu.Update(**ti); - return t_ret; - } - - - - - /* +++++++++++++++ Deleting ++++++++++++++++ */ - - /** Function to delete a face from the mesh. - NOTE: THIS FUNCTION ALSO UPDATE FN - */ - static void DeleteFace(MeshType &m, FaceType &f) - { - assert(&f >= &m.face.front() && &f <= &m.face.back()); - assert(!f.IsD()); - f.Dealloc(); - f.SetD(); - --m.fn; - } - - /** Function to delete a vertex from the mesh. - NOTE: THIS FUNCTION ALSO UPDATE vn - */ - static void DeleteVertex(MeshType &m, VertexType &v) - { - assert(&v >= &m.vert.front() && &v <= &m.vert.back()); - assert(!v.IsD()); - v.SetD(); - --m.vn; - } - - /** Function to delete an edge from the mesh. - NOTE: THIS FUNCTION ALSO UPDATE en - */ - static void DeleteEdge(MeshType &m, EdgeType &e) - { - assert(&e >= &m.edge.front() && &e <= &m.edge.back()); - assert(!e.IsD()); - e.SetD(); - --m.en; - } - - // /** Function to delete a hedge from the mesh. - // NOTE: THIS FUNCTION ALSO UPDATE en - // */ - // static void DeleteHEdge(MeshType &m, HEdgeType &h) - // { - // assert(&h >= &m.hedge.front() && &h <= &m.hedge.back()); - // assert(!h.IsD()); - // h.SetD(); - // --m.hn; - // } - - - /** Function to delete a tetra from the mesh. - NOTE: THIS FUNCTION ALSO UPDATE tn - */ - static void DeleteTetra(MeshType &m, TetraType &t) - { - assert(&t >= &m.tetra.front() && &t <= &m.tetra.back()); - assert(!t.IsD()); - t.SetD(); - --m.tn; - } - - - /* - Function to rearrange the vertex vector according to a given index permutation - the permutation is vector such that after calling this function - - m.vert[ newVertIndex[i] ] = m.vert[i]; - - e.g. newVertIndex[i] is the new index of the vertex i - - */ - static void PermutateVertexVector(MeshType &m, PointerUpdater &pu) - { - if (m.vert.empty()) - return; - for (size_t i = 0; i < m.vert.size(); ++i) - { - if (pu.remap[i] < size_t(m.vn)) - { - assert(!m.vert[i].IsD()); - m.vert[pu.remap[i]].ImportData(m.vert[i]); - if (HasVFAdjacency(m)) - { - if (m.vert[i].IsVFInitialized()) - { - m.vert[pu.remap[i]].VFp() = m.vert[i].cVFp(); - m.vert[pu.remap[i]].VFi() = m.vert[i].cVFi(); - } - else - m.vert[pu.remap[i]].VFClear(); - } - if (HasVEAdjacency(m)) - { - if (m.vert[i].IsVEInitialized()) - { - m.vert[pu.remap[i]].VEp() = m.vert[i].cVEp(); - m.vert[pu.remap[i]].VEi() = m.vert[i].cVEi(); - } - else - m.vert[pu.remap[i]].VEClear(); - } - } - } - - // reorder the optional atttributes in m.vert_attr to reflect the changes - ReorderAttribute(m.vert_attr, pu.remap, m); - - // setup the pointer updater - pu.oldBase = &m.vert[0]; - pu.oldEnd = &m.vert.back() + 1; - - // resize - m.vert.resize(m.vn); - - // setup the pointer updater - pu.newBase = (m.vert.empty()) ? 0 : &m.vert[0]; - pu.newEnd = (m.vert.empty()) ? 0 : &m.vert.back() + 1; - - // resize the optional atttributes in m.vert_attr to reflect the changes - ResizeAttribute(m.vert_attr, m.vn, m); - - // Loop on the face to update the pointers FV relation (vertex refs) - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if (!(*fi).IsD()) - for (int i = 0; i < fi->VN(); ++i) - { - size_t oldIndex = (*fi).V(i) - pu.oldBase; - assert(pu.oldBase <= (*fi).V(i) && oldIndex < pu.remap.size()); - (*fi).V(i) = pu.newBase + pu.remap[oldIndex]; - } - // Loop on the edges to update the pointers EV relation - if (HasEVAdjacency(m)) - for (EdgeIterator ei = m.edge.begin(); ei != m.edge.end(); ++ei) - if (!(*ei).IsD()) - { - pu.Update((*ei).V(0)); - pu.Update((*ei).V(1)); - } - } - - static void CompactEveryVector(MeshType &m) - { - CompactVertexVector(m); - CompactEdgeVector(m); - CompactFaceVector(m); - CompactTetraVector(m); - } - - /*! - \brief Compact vector of vertices removing deleted elements. - Deleted elements are put to the end of the vector and the vector is resized. Order between elements is preserved but not their position (hence the PointerUpdater) - After calling this function the \c IsD() test in the scanning a vector, is no more necessary. - - \warning It should not be called when TemporaryData is active (but works correctly if attributes are present) - */ - static void CompactVertexVector(MeshType &m, PointerUpdater &pu) - { - // If already compacted fast return please! - if (m.vn == (int)m.vert.size()) - return; - - // newVertIndex [ ] gives you the new position of the vertex in the vector; - pu.remap.resize(m.vert.size(), std::numeric_limits::max()); - - size_t pos = 0; - size_t i = 0; - - for (i = 0; i < m.vert.size(); ++i) - { - if (!m.vert[i].IsD()) - { - pu.remap[i] = pos; - ++pos; - } - } - assert((int)pos == m.vn); - - PermutateVertexVector(m, pu); - } - - /*! \brief Wrapper without the PointerUpdater. */ - static void CompactVertexVector(MeshType &m) - { - PointerUpdater pu; - CompactVertexVector(m, pu); - } - - /*! - \brief Compact vector of edges removing deleted elements. - - Deleted elements are put to the end of the vector and the vector is resized. Order between elements is preserved but not their position (hence the PointerUpdater) - After calling this function the \c IsD() test in the scanning a vector, is no more necessary. - - \warning It should not be called when TemporaryData is active (but works correctly if attributes are present) - */ - static void CompactEdgeVector(MeshType &m, PointerUpdater &pu) - { - // If already compacted fast return please! - if (m.en == (int)m.edge.size()) - return; - - // remap [ ] gives you the new position of the edge in the vector; - pu.remap.resize(m.edge.size(), std::numeric_limits::max()); - - size_t pos = 0; - size_t i = 0; - - for (i = 0; i < m.edge.size(); ++i) - { - if (!m.edge[i].IsD()) - { - pu.remap[i] = pos; - ++pos; - } - } - assert((int)pos == m.en); - - // the actual copying of the data. - for (size_t i = 0; i < m.edge.size(); ++i) - { - if (pu.remap[i] < size_t(m.en)) // uninitialized entries in the remap vector has max_int value; - { - assert(!m.edge[i].IsD()); - m.edge[pu.remap[i]].ImportData(m.edge[i]); - // copy the vertex reference (they are not data!) - m.edge[pu.remap[i]].V(0) = m.edge[i].cV(0); - m.edge[pu.remap[i]].V(1) = m.edge[i].cV(1); - // Now just copy the adjacency pointers (without changing them, to be done later) - if (HasVEAdjacency(m)) - //if (m.edge[i].cVEp(0)!=0) - { - m.edge[pu.remap[i]].VEp(0) = m.edge[i].cVEp(0); - m.edge[pu.remap[i]].VEi(0) = m.edge[i].cVEi(0); - m.edge[pu.remap[i]].VEp(1) = m.edge[i].cVEp(1); - m.edge[pu.remap[i]].VEi(1) = m.edge[i].cVEi(1); - } - if (HasEEAdjacency(m)) - // if (m.edge[i].cEEp(0)!=0) - { - m.edge[pu.remap[i]].EEp(0) = m.edge[i].cEEp(0); - m.edge[pu.remap[i]].EEi(0) = m.edge[i].cEEi(0); - m.edge[pu.remap[i]].EEp(1) = m.edge[i].cEEp(1); - m.edge[pu.remap[i]].EEi(1) = m.edge[i].cEEi(1); - } - } - } - - // reorder the optional attributes in m.vert_attr to reflect the changes - ReorderAttribute(m.edge_attr, pu.remap, m); - - // setup the pointer updater - pu.oldBase = &m.edge[0]; - pu.oldEnd = &m.edge.back() + 1; - - // THE resize - m.edge.resize(m.en); - - // setup the pointer updater - pu.newBase = (m.edge.empty()) ? 0 : &m.edge[0]; - pu.newEnd = (m.edge.empty()) ? 0 : &m.edge.back() + 1; - - // resize the optional atttributes in m.vert_attr to reflect the changes - ResizeAttribute(m.edge_attr, m.en, m); - - // Loop on the vertices to update the pointers of VE relation - if (HasVEAdjacency(m)) - for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if (!(*vi).IsD()) - pu.Update((*vi).VEp()); - - // Loop on the edges to update the pointers EE VE relation - for (EdgeIterator ei = m.edge.begin(); ei != m.edge.end(); ++ei) - for (unsigned int i = 0; i < 2; ++i) - { - if (HasVEAdjacency(m)) - pu.Update((*ei).VEp(i)); - if (HasEEAdjacency(m)) - pu.Update((*ei).EEp(i)); - } - } - - /*! \brief Wrapper without the PointerUpdater. */ - static void CompactEdgeVector(MeshType &m) - { - PointerUpdater pu; - CompactEdgeVector(m, pu); - } - - - /*! - \brief Compact face vector by removing deleted elements. - - Deleted elements are put to the end of the vector and the vector is resized. - Order between elements is preserved, but not their position (hence the PointerUpdater) - Immediately after calling this function the \c IsD() test during the scanning a vector, is no more necessary. - \warning It should not be called when some TemporaryData is active (but works correctly if attributes are present) - */ - static void CompactFaceVector(MeshType &m, PointerUpdater &pu) - { - // If already compacted fast return please! - if (m.fn == (int)m.face.size()) - return; - - // newFaceIndex [ ] gives you the new position of the face in the vector; - pu.remap.resize(m.face.size(), std::numeric_limits::max()); - - size_t pos = 0; - for (size_t i = 0; i < m.face.size(); ++i) - { - if (!m.face[i].IsD()) - { - if (pos != i) - { - m.face[pos].ImportData(m.face[i]); - if (FaceType::HasPolyInfo()) - { - m.face[pos].Dealloc(); - m.face[pos].Alloc(m.face[i].VN()); - } - for (int j = 0; j < m.face[i].VN(); ++j) - m.face[pos].V(j) = m.face[i].V(j); - - if (HasVFAdjacency(m)) - for (int j = 0; j < m.face[i].VN(); ++j) - { - if (m.face[i].IsVFInitialized(j)) - { - m.face[pos].VFp(j) = m.face[i].cVFp(j); - m.face[pos].VFi(j) = m.face[i].cVFi(j); - } - else - m.face[pos].VFClear(j); - } - if (HasFFAdjacency(m)) - for (int j = 0; j < m.face[i].VN(); ++j) - { - m.face[pos].FFp(j) = m.face[i].cFFp(j); - m.face[pos].FFi(j) = m.face[i].cFFi(j); - } - } - pu.remap[i] = pos; - ++pos; - } - } - assert((int)pos == m.fn); - - // reorder the optional atttributes in m.face_attr to reflect the changes - ReorderAttribute(m.face_attr, pu.remap, m); - - FacePointer fbase = &m.face[0]; - - // Loop on the vertices to correct VF relation - if (HasVFAdjacency(m)) - { - for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if (!(*vi).IsD()) - { - if ((*vi).IsVFInitialized() && (*vi).VFp() != 0) - { - size_t oldIndex = (*vi).cVFp() - fbase; - assert(fbase <= (*vi).cVFp() && oldIndex < pu.remap.size()); - (*vi).VFp() = fbase + pu.remap[oldIndex]; - } - } - } - - // Loop on the faces to correct VF and FF relations - pu.oldBase = &m.face[0]; - pu.oldEnd = &m.face.back() + 1; - for (size_t i = m.fn; i < m.face.size(); ++i) - m.face[i].Dealloc(); - m.face.resize(m.fn); - pu.newBase = (m.face.empty()) ? 0 : &m.face[0]; - pu.newEnd = (m.face.empty()) ? 0 : &m.face.back() + 1; - - // resize the optional atttributes in m.face_attr to reflect the changes - ResizeAttribute(m.face_attr, m.fn, m); - - // now we update the various (not null) face pointers (inside VF and FF relations) - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if (!(*fi).IsD()) - { - if (HasVFAdjacency(m)) - for (int i = 0; i < (*fi).VN(); ++i) - if ((*fi).IsVFInitialized(i) && (*fi).VFp(i) != 0) - { - size_t oldIndex = (*fi).VFp(i) - fbase; - assert(fbase <= (*fi).VFp(i) && oldIndex < pu.remap.size()); - (*fi).VFp(i) = fbase + pu.remap[oldIndex]; - } - if (HasFFAdjacency(m)) - for (int i = 0; i < (*fi).VN(); ++i) - if ((*fi).cFFp(i) != 0) - { - size_t oldIndex = (*fi).FFp(i) - fbase; - assert(fbase <= (*fi).FFp(i) && oldIndex < pu.remap.size()); - (*fi).FFp(i) = fbase + pu.remap[oldIndex]; - } - } - } - - /*! \brief Wrapper without the PointerUpdater. */ - static void CompactFaceVector(MeshType &m) - { - PointerUpdater pu; - CompactFaceVector(m, pu); - } - - - /*! - \brief Compact tetra vector by removing deleted elements. - - Deleted elements are put to the end of the vector and the vector is resized. - Order between elements is preserved, but not their position (hence the PointerUpdater) - Immediately after calling this function the \c IsD() test during the scanning a vector, is no more necessary. - \warning It should not be called when some TemporaryData is active (but works correctly if attributes are present) - */ - static void CompactTetraVector(MeshType & m, PointerUpdater & pu) - { - //nothing to do - if (size_t(m.tn) == m.tetra.size()) - return; - - //init the remap - pu.remap.resize(m.tetra.size(), std::numeric_limits::max()); - - //cycle over all the tetras, pos is the last not D() position, I is the index - //when pos != i and !tetra[i].IsD() => we need to compact and update adj - size_t pos = 0; - for (size_t i = 0; i < m.tetra.size(); ++i) - { - if (!m.tetra.IsD()) - { - if (pos != i) - { - //import data - m.tetra[pos].ImportData(m.tetra[i]); - //import vertex refs - for (int j = 0; j < 4; ++j) - m.tetra[pos].V(j) = m.tetra[i].cV(j); - //import VT adj - if (HasVTAdjacency(m)) - for (int j = 0; j < 4; ++j) - { - if (m.tetra[i].IsVTInitialized(j)) - { - m.tetra[pos].VTp(j) = m.tetra[i].VTp(j); - m.tetra[pos].VTi(j) = m.tetra[i].VTi(j); - } - else - m.tetra[pos].VTClear(); - } - //import TT adj - if (HasTTAdjacency(m)) - for (int j = 0; j < 4; ++j) - { - m.tetra[pos].TTp(j) = m.tetra[i].cTTp(j); - m.tetra[pos].TTi(j) = m.tetra[i].cTTi(j); - } - } - //update remapping and advance pos - pu.remap[i] = pos; - ++pos; - } - } - - assert(size_t(m.tn) == pos); - //reorder the optional attributes in m.tetra_attr - ReorderAttribute(m.tetra_attr, pu.remap, m); - // resize the optional atttributes in m.tetra_attr to reflect the changes - ResizeAttribute(m.tetra_attr, m.tn, m); - - // Loop on the tetras to correct VT and TT relations - pu.oldBase = &m.tetra[0]; - pu.oldEnd = &m.tetra.back() + 1; - - m.tetra.resize(m.tn); - pu.newBase = (m.tetra.empty()) ? 0 : &m.tetra[0]; - pu.newEnd = (m.tetra.empty()) ? 0 : &m.tetra.back() + 1; - - TetraPointer tbase = &m.tetra[0]; - - //Loop on the vertices to correct VT relation (since we moved things around) - if (HasVTAdjacency(m)) - { - for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if (!(*vi).IsD()) - { - if ((*vi).IsVTInitialized() && (*vi).VTp() != 0) - { - size_t oldIndex = (*vi).cVTp() - tbase; - assert(tbase <= (*vi).cVTp() && oldIndex < pu.remap.size()); - (*vi).VTp() = tbase + pu.remap[oldIndex]; - } - } - } - - // Loop on the tetras to correct the VT and TT relations - for (TetraIterator ti = m.tetra.begin(); ti != m.tetra.end(); ++ti) - if (!(*ti).IsD()) - { - //VT - if (HasVTAdjacency(m)) - for (int i = 0; i < 4; ++i) - if ((*ti).IsVTInitialized(i) && (*ti).VTp(i) != 0) - { - size_t oldIndex = (*ti).VTp(i) - fbase; - assert(tbase <= (*ti).VTp(i) && oldIndex < pu.remap.size()); - (*ti).VTp(i) = tbase + pu.remap[oldIndex]; - } - //TT - if (HasTTAdjacency(m)) - for (int i = 0; i < 4; ++i) - if ((*ti).cTTp(i) != 0) - { - size_t oldIndex = (*ti).TTp(i) - tbase; - assert(tbase <= (*ti).TTp(i) && oldIndex < pu.remap.size()); - (*ti).TTp(i) = tbase + pu.remap[oldIndex]; - } - } - } - - /*! \brief Wrapper without the PointerUpdater. */ - static void CompactTetraVector(MeshType &m) - { - PointerUpdater pu; - CompactTetraVector(m, pu); - } - -public: - /*! \brief Check if an handle to a Per-Vertex Attribute is valid - */ - template - static bool IsValidHandle(MeshType &m, const typename MeshType::template PerVertexAttributeHandle &a) - { - if (a._handle == NULL) - return false; - for (AttrIterator i = m.vert_attr.begin(); i != m.vert_attr.end(); ++i) - if ((*i).n_attr == a.n_attr) - return true; - return false; - } - - /*! \brief Add a Per-Vertex Attribute of the given ATTR_TYPE with the given name. - - No attribute with that name must exists (even of different type) - */ - template - static - typename MeshType::template PerVertexAttributeHandle - AddPerVertexAttribute(MeshType &m, std::string name) - { - PAIte i; - PointerToAttribute h; - h._name = name; - if (!name.empty()) - { - i = m.vert_attr.find(h); - assert(i == m.vert_attr.end()); // an attribute with this name exists - } - - h._sizeof = sizeof(ATTR_TYPE); - h._padding = 0; - h._handle = new SimpleTempData(m.vert); - h._type = typeid(ATTR_TYPE); - m.attrn++; - h.n_attr = m.attrn; - std::pair res = m.vert_attr.insert(h); - return typename MeshType::template PerVertexAttributeHandle(res.first->_handle, res.first->n_attr); - } - - template - static typename MeshType::template PerVertexAttributeHandle - AddPerVertexAttribute(MeshType &m) - { - return AddPerVertexAttribute(m, std::string("")); - } - - /*! \brief gives a handle to a per-vertex attribute with a given name and ATTR_TYPE - \returns a valid handle. If the name is not empty and an attribute with that name and type exists returns a handle to it. - Otherwise return a hanlde to a newly created. - */ - template - static - typename MeshType::template PerVertexAttributeHandle - GetPerVertexAttribute(MeshType &m, std::string name = std::string("")) - { - typename MeshType::template PerVertexAttributeHandle h; - if (!name.empty()) - { - h = FindPerVertexAttribute(m, name); - if (IsValidHandle(m, h)) - return h; - } - return AddPerVertexAttribute(m, name); - } - - /*! \brief Try to retrieve an handle to an attribute with a given name and ATTR_TYPE - \returns a invalid handle if no attribute with that name and type exists. - */ - template - static typename MeshType::template PerVertexAttributeHandle - FindPerVertexAttribute(MeshType &m, const std::string &name) - { - assert(!name.empty()); - PointerToAttribute h1; - h1._name = name; - typename std::set::iterator i; - - i = m.vert_attr.find(h1); - if (i != m.vert_attr.end()) - if ((*i)._sizeof == sizeof(ATTR_TYPE)) - { - if ((*i)._padding != 0) - { - PointerToAttribute attr = (*i); // copy the PointerToAttribute - m.vert_attr.erase(i); // remove it from the set - FixPaddedPerVertexAttribute(m, attr); - std::pair new_i = m.vert_attr.insert(attr); // insert the modified PointerToAttribute - assert(new_i.second); - i = new_i.first; - } - return typename MeshType::template PerVertexAttributeHandle((*i)._handle, (*i).n_attr); - } - return typename MeshType::template PerVertexAttributeHandle(NULL, 0); - } - - /*! \brief query the mesh for all the attributes per vertex - \returns the name of all attributes with a non-empy name. - */ - template - static void GetAllPerVertexAttribute(MeshType &m, std::vector &all) - { - all.clear(); - typename std::set::const_iterator i; - for (i = m.vert_attr.begin(); i != m.vert_attr.end(); ++i) - if (!(*i)._name.empty()) - { - typename MeshType::template PerVertexAttributeHandle hh; - hh = Allocator::template FindPerVertexAttribute(m, (*i)._name); - if (IsValidHandle(m, hh)) - all.push_back((*i)._name); - } - } - - template - static void - ClearPerVertexAttribute(MeshType &m, typename MeshType::template PerVertexAttributeHandle &h, const ATTR_TYPE &initVal = ATTR_TYPE()) - { - typename std::set::iterator i; - for (i = m.vert_attr.begin(); i != m.vert_attr.end(); ++i) - if ((*i)._handle == h._handle) - { - for (typename MeshType::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) - h[vi] = initVal; - return; - } - assert(0); - } - - /*! \brief If the per-vertex attribute exists, delete it. - */ - template - static void - DeletePerVertexAttribute(MeshType &m, typename MeshType::template PerVertexAttributeHandle &h) - { - typename std::set::iterator i; - for (i = m.vert_attr.begin(); i != m.vert_attr.end(); ++i) - if ((*i)._handle == h._handle) - { - delete ((SimpleTempData *)(*i)._handle); - m.vert_attr.erase(i); - return; - } - } - - // Generic DeleteAttribute. - // It must not crash if you try to delete a non existing attribute, - // because you do not have a way of asking for a handle of an attribute for which you do not know the type. - static bool DeletePerVertexAttribute(MeshType &m, std::string name) - { - AttrIterator i; - PointerToAttribute h1; - h1._name = name; - i = m.vert_attr.find(h1); - if (i == m.vert_attr.end()) - return false; - delete ((SimpleTempDataBase *)(*i)._handle); - m.vert_attr.erase(i); - return true; - } - - /// Per Edge Attributes - template - static bool IsValidHandle(MeshType &m, const typename MeshType::template PerEdgeAttributeHandle &a) - { - if (a._handle == NULL) - return false; - for (AttrIterator i = m.edge_attr.begin(); i != m.edge_attr.end(); ++i) - if ((*i).n_attr == a.n_attr) - return true; - return false; - } - - template - static - typename MeshType::template PerEdgeAttributeHandle - AddPerEdgeAttribute(MeshType &m, std::string name) - { - PAIte i; - PointerToAttribute h; - h._name = name; - if (!name.empty()) - { - i = m.edge_attr.find(h); - assert(i == m.edge_attr.end()); // an attribute with this name exists - } - h._sizeof = sizeof(ATTR_TYPE); - h._padding = 0; - // h._typename = typeid(ATTR_TYPE).name(); - h._handle = new SimpleTempData(m.edge); - h._type = typeid(ATTR_TYPE); - m.attrn++; - h.n_attr = m.attrn; - std::pair res = m.edge_attr.insert(h); - return typename MeshType::template PerEdgeAttributeHandle(res.first->_handle, res.first->n_attr); - } - - template - static - typename MeshType::template PerEdgeAttributeHandle - AddPerEdgeAttribute(MeshType &m) - { - return AddPerEdgeAttribute(m, std::string("")); - } - - /*! \brief gives a handle to a per-edge attribute with a given name and ATTR_TYPE - \returns a valid handle. If the name is not empty and an attribute with that name and type exists returns a handle to it. - Otherwise return a hanlde to a newly created. - */ - template - static - typename MeshType::template PerEdgeAttributeHandle - GetPerEdgeAttribute(MeshType &m, std::string name = std::string("")) - { - typename MeshType::template PerEdgeAttributeHandle h; - if (!name.empty()) - { - h = FindPerEdgeAttribute(m, name); - if (IsValidHandle(m, h)) - return h; - } - return AddPerEdgeAttribute(m, name); - } - - template - static - typename MeshType::template PerEdgeAttributeHandle - FindPerEdgeAttribute(MeshType &m, const std::string &name) - { - assert(!name.empty()); - PointerToAttribute h1; - h1._name = name; - typename std::set::const_iterator i; - - i = m.edge_attr.find(h1); - if (i != m.edge_attr.end()) - if ((*i)._sizeof == sizeof(ATTR_TYPE)) - { - if ((*i)._padding != 0) - { - PointerToAttribute attr = (*i); // copy the PointerToAttribute - m.edge_attr.erase(i); // remove it from the set - FixPaddedPerEdgeAttribute(m, attr); - std::pair new_i = m.edge_attr.insert(attr); // insert the modified PointerToAttribute - assert(new_i.second); - i = new_i.first; - } - return typename MeshType::template PerEdgeAttributeHandle((*i)._handle, (*i).n_attr); - } - - return typename MeshType::template PerEdgeAttributeHandle(NULL, 0); - } - - template - static void GetAllPerEdgeAttribute(const MeshType &m, std::vector &all) - { - all.clear(); - typename std::set::const_iterator i; - for (i = m.edge_attr.begin(); i != m.edge_attr.end(); ++i) - if (!(*i)._name.empty()) - { - typename MeshType::template PerEdgeAttributeHandle hh; - hh = Allocator::template FindPerEdgeAttribute(m, (*i)._name); - if (IsValidHandle(m, hh)) - all.push_back((*i)._name); - } - } - - /*! \brief If the per-edge attribute exists, delete it. - */ - template - static void - DeletePerEdgeAttribute(MeshType &m, typename MeshType::template PerEdgeAttributeHandle &h) - { - typename std::set::iterator i; - for (i = m.edge_attr.begin(); i != m.edge_attr.end(); ++i) - if ((*i)._handle == h._handle) - { - delete ((SimpleTempData *)(*i)._handle); - m.edge_attr.erase(i); - return; - } - } - - // Generic DeleteAttribute. - // It must not crash if you try to delete a non existing attribute, - // because you do not have a way of asking for a handle of an attribute for which you do not know the type. - static bool DeletePerEdgeAttribute(MeshType &m, std::string name) - { - AttrIterator i; - PointerToAttribute h1; - h1._name = name; - i = m.edge_attr.find(h1); - if (i == m.edge_attr.end()) - return false; - delete ((SimpleTempDataBase *)(*i)._handle); - m.edge_attr.erase(i); - return true; - } - - /// Per Tetra Attributes - template - static bool IsValidHandle(MeshType & m, const typename MeshType::template PerTetraAttributeHandle & a) - { - if (a._handle == NULL) - return false; - for (AttrIterator i = m.tetra_attr.begin(); i != m.tetra_attr.end(); ++i) - if ((*i).n_attr == a.n_attr) - return true; - return false; - } - - template - static typename MeshType::template PerTetraAttributeHandle AddPerTetraAttribute(MeshType & m, std::string name) - { - PAIte i; - PointerToAttribute h; - h._name = name; - if (!name.empty()) - { - i = m.tetra_attr.find(h); - assert(i == m.tetra_attr.end()); - } - - h._sizeof = sizeof(ATTR_TYPE); - h._padding = 0; - h._handle = new SimpleTempData(m.tetra); - h._type = typeid(ATTR_TYPE); - m.attrn++; - h.n_attr = m.attrn; - std::pair res = m.tetra_attr.insert(h); - return typename MeshType::template PerTetraAttributeHandle(res.first->_handle, res.first->n_attr); - } - - template - static typename MeshType::template PerTetraAttributeHandle AddPerTetraAttribute(MeshType &m) - { - return AddPerTetraAttribute(m, std::string("")); - } - - /*! \brief gives a handle to a per-tetra attribute with a given name and ATTR_TYPE - \returns a valid handle. If the name is not empty and an attribute with that name and type exists returns a handle to it. - Otherwise return a hanlde to a newly created. - */ - template - static typename MeshType::template PerTetraAttributeHandle GetPerTetraAttribute(MeshType &m, std::string name = std::string("")) - { - typename MeshType::template PerTetraAttributeHandle h; - if (!name.empty()) - { - h = FindPerTetraAttribute(m, name); - if (IsValidHandle(m, h)) - return h; - } - return AddPerTetraAttribute(m, name); - } - - template - static typename MeshType::template PerTetraAttributeHandle FindPerTetraAttribute(MeshType &m, const std::string &name) - { - assert(!name.empty()); - PointerToAttribute h1; - h1._name = name; - typename std::set::iterator i; - - i = m.tetra_attr.find(h1); - if (i != m.tetra_attr.end()) - if ((*i)._sizeof == sizeof(ATTR_TYPE)) - { - if ((*i)._padding != 0) - { - PointerToAttribute attr = (*i); // copy the PointerToAttribute - m.tetra_attr.erase(i); // remove it from the set - FixPaddedPerTetraAttribute(m, attr); - std::pair new_i = m.tetra_attr.insert(attr); // insert the modified PointerToAttribute - assert(new_i.second); - i = new_i.first; - } - return typename MeshType::template PerTetraAttributeHandle((*i)._handle, (*i).n_attr); - } - return typename MeshType::template PerTetraAttributeHandle(NULL, 0); - } - - template - static void GetAllPerTetraAttribute(MeshType &m, std::vector &all) - { - all.clear(); - typename std::set::const_iterator i; - for (i = m.tetra_attr.begin(); i != m.tetra_attr.end(); ++i) - if (!(*i)._name.empty()) - { - typename MeshType::template PerTetraAttributeHandle hh; - hh = Allocator::template FindPerTetraAttribute(m, (*i)._name); - if (IsValidHandle(m, hh)) - all.push_back((*i)._name); - } - } - - /*! \brief If the per-face attribute exists, delete it. - */ - template - static void DeletePerTetraAttribute(MeshType &m, typename MeshType::template PerTetraAttributeHandle &h) - { - typename std::set::iterator i; - for (i = m.tetra_attr.begin(); i != m.tetra_attr.end(); ++i) - if ((*i)._handle == h._handle) - { - delete ((SimpleTempData *)(*i)._handle); - m.tetra_attr.erase(i); - return; - } - } - - // Generic DeleteAttribute. - // It must not crash if you try to delete a non existing attribute, - // because you do not have a way of asking for a handle of an attribute for which you do not know the type. - static bool DeletePerTetraAttribute(MeshType &m, std::string name) - { - AttrIterator i; - PointerToAttribute h1; - h1._name = name; - i = m.tetra_attr.find(h1); - if (i == m.tetra_attr.end()) - return false; - delete ((SimpleTempDataBase *)(*i)._handle); - m.tetra_attr.erase(i); - return true; - } - - - /// Per Face Attributes - template - static bool IsValidHandle(MeshType &m, const typename MeshType::template PerFaceAttributeHandle &a) - { - if (a._handle == NULL) - return false; - for (AttrIterator i = m.face_attr.begin(); i != m.face_attr.end(); ++i) - if ((*i).n_attr == a.n_attr) - return true; - return false; - } - - template - static - typename MeshType::template PerFaceAttributeHandle - AddPerFaceAttribute(MeshType &m, std::string name) - { - PAIte i; - PointerToAttribute h; - h._name = name; - if (!name.empty()) - { - i = m.face_attr.find(h); - assert(i == m.face_attr.end()); // an attribute with this name exists - } - - h._sizeof = sizeof(ATTR_TYPE); - h._padding = 0; - h._handle = new SimpleTempData(m.face); - h._type = typeid(ATTR_TYPE); - m.attrn++; - h.n_attr = m.attrn; - std::pair res = m.face_attr.insert(h); - return typename MeshType::template PerFaceAttributeHandle(res.first->_handle, res.first->n_attr); - } - - template - static - typename MeshType::template PerFaceAttributeHandle - AddPerFaceAttribute(MeshType &m) - { - return AddPerFaceAttribute(m, std::string("")); - } - - /*! \brief gives a handle to a per-edge attribute with a given name and ATTR_TYPE - \returns a valid handle. If the name is not empty and an attribute with that name and type exists returns a handle to it. - Otherwise return a hanlde to a newly created. - */ - template - static - typename MeshType::template PerFaceAttributeHandle - GetPerFaceAttribute(MeshType &m, std::string name = std::string("")) - { - typename MeshType::template PerFaceAttributeHandle h; - if (!name.empty()) - { - h = FindPerFaceAttribute(m, name); - if (IsValidHandle(m, h)) - return h; - } - return AddPerFaceAttribute(m, name); - } - - template - static - typename MeshType::template PerFaceAttributeHandle - FindPerFaceAttribute(MeshType &m, const std::string &name) - { - assert(!name.empty()); - PointerToAttribute h1; - h1._name = name; - typename std::set::iterator i; - - i = m.face_attr.find(h1); - if (i != m.face_attr.end()) - if ((*i)._sizeof == sizeof(ATTR_TYPE)) - { - if ((*i)._padding != 0) - { - PointerToAttribute attr = (*i); // copy the PointerToAttribute - m.face_attr.erase(i); // remove it from the set - FixPaddedPerFaceAttribute(m, attr); - std::pair new_i = m.face_attr.insert(attr); // insert the modified PointerToAttribute - assert(new_i.second); - i = new_i.first; - } - return typename MeshType::template PerFaceAttributeHandle((*i)._handle, (*i).n_attr); - } - return typename MeshType::template PerFaceAttributeHandle(NULL, 0); - } - - template - static void GetAllPerFaceAttribute(MeshType &m, std::vector &all) - { - all.clear(); - typename std::set::const_iterator i; - for (i = m.face_attr.begin(); i != m.face_attr.end(); ++i) - if (!(*i)._name.empty()) - { - typename MeshType::template PerFaceAttributeHandle hh; - hh = Allocator::template FindPerFaceAttribute(m, (*i)._name); - if (IsValidHandle(m, hh)) - all.push_back((*i)._name); - } - } - - /*! \brief If the per-face attribute exists, delete it. - */ - template - static void DeletePerFaceAttribute(MeshType &m, typename MeshType::template PerFaceAttributeHandle &h) - { - typename std::set::iterator i; - for (i = m.face_attr.begin(); i != m.face_attr.end(); ++i) - if ((*i)._handle == h._handle) - { - delete ((SimpleTempData *)(*i)._handle); - m.face_attr.erase(i); - return; - } - } - - // Generic DeleteAttribute. - // It must not crash if you try to delete a non existing attribute, - // because you do not have a way of asking for a handle of an attribute for which you do not know the type. - static bool DeletePerFaceAttribute(MeshType &m, std::string name) - { - AttrIterator i; - PointerToAttribute h1; - h1._name = name; - i = m.face_attr.find(h1); - if (i == m.face_attr.end()) - return false; - delete ((SimpleTempDataBase *)(*i)._handle); - m.face_attr.erase(i); - return true; - } - - /// Per Mesh Attributes - template - static bool IsValidHandle(MeshType &m, const typename MeshType::template PerMeshAttributeHandle &a) - { - if (a._handle == NULL) - return false; - for (AttrIterator i = m.mesh_attr.begin(); i != m.mesh_attr.end(); ++i) - if ((*i).n_attr == a.n_attr) - return true; - return false; - } - - template - static - typename MeshType::template PerMeshAttributeHandle - AddPerMeshAttribute(MeshType &m, std::string name) - { - PAIte i; - PointerToAttribute h; - h._name = name; - if (!name.empty()) - { - i = m.mesh_attr.find(h); - assert(i == m.mesh_attr.end()); // an attribute with this name exists - } - h._sizeof = sizeof(ATTR_TYPE); - h._padding = 0; - h._handle = new Attribute(); - h._type = typeid(ATTR_TYPE); - m.attrn++; - h.n_attr = m.attrn; - std::pair res = m.mesh_attr.insert(h); - return typename MeshType::template PerMeshAttributeHandle(res.first->_handle, res.first->n_attr); - } - - /*! \brief gives a handle to a per-edge attribute with a given name and ATTR_TYPE - \returns a valid handle. If the name is not empty and an attribute with that name and type exists returns a handle to it. - Otherwise return a hanlde to a newly created. - */ - template - static - typename MeshType::template PerMeshAttributeHandle - GetPerMeshAttribute(MeshType &m, std::string name = std::string("")) - { - typename MeshType::template PerMeshAttributeHandle h; - if (!name.empty()) - { - h = FindPerMeshAttribute(m, name); - if (IsValidHandle(m, h)) - return h; - } - return AddPerMeshAttribute(m, name); - } - - template - static - typename MeshType::template PerMeshAttributeHandle - FindPerMeshAttribute(MeshType &m, const std::string &name) - { - assert(!name.empty()); - PointerToAttribute h1; - h1._name = name; - typename std::set::iterator i; - - i = m.mesh_attr.find(h1); - if (i != m.mesh_attr.end()) - if ((*i)._sizeof == sizeof(ATTR_TYPE)) - { - if ((*i)._padding != 0) - { - PointerToAttribute attr = (*i); // copy the PointerToAttribute - m.mesh_attr.erase(i); // remove it from the set - FixPaddedPerMeshAttribute(m, attr); - std::pair new_i = m.mesh_attr.insert(attr); // insert the modified PointerToAttribute - assert(new_i.second); - i = new_i.first; - } - - return typename MeshType::template PerMeshAttributeHandle((*i)._handle, (*i).n_attr); - } - - return typename MeshType::template PerMeshAttributeHandle(NULL, 0); - } - - template - static void GetAllPerMeshAttribute(const MeshType &m, std::vector &all) - { - typename std::set::iterator i; - for (i = m.mesh_attr.begin(); i != m.mesh_attr.end(); ++i) - if ((*i)._sizeof == sizeof(ATTR_TYPE)) - all.push_back((*i)._name); - } - - /*! \brief If the per-mesh attribute exists, delete it. - */ - template - static void DeletePerMeshAttribute(MeshType &m, typename MeshType::template PerMeshAttributeHandle &h) - { - typename std::set::iterator i; - for (i = m.mesh_attr.begin(); i != m.mesh_attr.end(); ++i) - if ((*i)._handle == h._handle) - { - delete ((Attribute *)(*i)._handle); - m.mesh_attr.erase(i); - return; - } - } - - // Generic DeleteAttribute. - // It must not crash if you try to delete a non existing attribute, - // because you do not have a way of asking for a handle of an attribute for which you do not know the type. - static bool DeletePerMeshAttribute(MeshType &m, std::string name) - { - AttrIterator i; - PointerToAttribute h1; - h1._name = name; - i = m.mesh_attr.find(h1); - if (i == m.mesh_attr.end()) - return false; - delete ((SimpleTempDataBase *)(*i)._handle); - m.mesh_attr.erase(i); - return true; - } - - template - static void FixPaddedPerVertexAttribute(MeshType &m, PointerToAttribute &pa) - { - - // create the container of the right type - SimpleTempData *_handle = new SimpleTempData(m.vert); - - // copy the padded container in the new one - _handle->Resize(m.vert.size()); - for (size_t i = 0; i < m.vert.size(); ++i) - { - ATTR_TYPE *dest = &(*_handle)[i]; - char *ptr = (char *)(((SimpleTempDataBase *)pa._handle)->DataBegin()); - memcpy((void *)dest, - (void *)&(ptr[i * pa._sizeof]), sizeof(ATTR_TYPE)); - } - - // remove the padded container - delete ((SimpleTempDataBase *)pa._handle); - - // update the pointer to data - pa._sizeof = sizeof(ATTR_TYPE); - - // update the pointer to data - pa._handle = _handle; - - // zero the padding - pa._padding = 0; - } - template - static void FixPaddedPerEdgeAttribute(MeshType &m, PointerToAttribute &pa) - { - - // create the container of the right type - SimpleTempData *_handle = new SimpleTempData(m.edge); - - // copy the padded container in the new one - _handle->Resize(m.edge.size()); - for (size_t i = 0; i < m.edge.size(); ++i) - { - ATTR_TYPE *dest = &(*_handle)[i]; - char *ptr = (char *)(((SimpleTempDataBase *)pa._handle)->DataBegin()); - memcpy((void *)dest, - (void *)&(ptr[i * pa._sizeof]), sizeof(ATTR_TYPE)); - } - - // remove the padded container - delete ((SimpleTempDataBase *)pa._handle); - - // update the pointer to data - pa._sizeof = sizeof(ATTR_TYPE); - - // update the pointer to data - pa._handle = _handle; - - // zero the padding - pa._padding = 0; - } - - template - static void FixPaddedPerFaceAttribute(MeshType &m, PointerToAttribute &pa) - { - - // create the container of the right type - SimpleTempData *_handle = new SimpleTempData(m.face); - - // copy the padded container in the new one - _handle->Resize(m.face.size()); - for (size_t i = 0; i < m.face.size(); ++i) - { - ATTR_TYPE *dest = &(*_handle)[i]; - char *ptr = (char *)(((SimpleTempDataBase *)pa._handle)->DataBegin()); - memcpy((void *)dest, - (void *)&(ptr[i * pa._sizeof]), sizeof(ATTR_TYPE)); - } - - // remove the padded container - delete ((SimpleTempDataBase *)pa._handle); - - // update the pointer to data - pa._sizeof = sizeof(ATTR_TYPE); - - // update the pointer to data - pa._handle = _handle; - - // zero the padding - pa._padding = 0; - } - - template - static void FixPaddedPerTetraAttribute(MeshType &m, PointerToAttribute &pa) - { - - // create the container of the right type - SimpleTempData *_handle = new SimpleTempData(m.tetra); - - // copy the padded container in the new one - _handle->Resize(m.tetra.size()); - for (size_t i = 0; i < m.tetra.size(); ++i) - { - ATTR_TYPE *dest = &(*_handle)[i]; - char *ptr = (char *)(((SimpleTempDataBase *)pa._handle)->DataBegin()); - memcpy((void *)dest, - (void *)&(ptr[i * pa._sizeof]), sizeof(ATTR_TYPE)); - } - - // remove the padded container - delete ((SimpleTempDataBase *)pa._handle); - - // update the pointer to data - pa._sizeof = sizeof(ATTR_TYPE); - - // update the pointer to data - pa._handle = _handle; - - // zero the padding - pa._padding = 0; - } - - template - static void FixPaddedPerMeshAttribute(MeshType & /* m */, PointerToAttribute &pa) - { - - // create the container of the right type - Attribute *_handle = new Attribute(); - - // copy the padded container in the new one - char *ptr = (char *)(((Attribute *)pa._handle)->DataBegin()); - memcpy((void *)_handle->attribute, (void *)&(ptr[0]), sizeof(ATTR_TYPE)); - - // remove the padded container - delete ((Attribute *)pa._handle); - - // update the pointer to data - pa._sizeof = sizeof(ATTR_TYPE); - - // update the pointer to data - pa._handle = _handle; - - // zero the padding - pa._padding = 0; - } - -}; // end Allocator class - -/** @} */ // end doxygen group trimesh -} // end namespace tri -} // end namespace vcg - -#endif diff --git a/vcg/complex/tetrahedron/append.h b/vcg/complex/tetrahedron/append.h deleted file mode 100644 index 1639d73d..00000000 --- a/vcg/complex/tetrahedron/append.h +++ /dev/null @@ -1,456 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004-2016 \/)\/ * -* 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_TETRAAPPEND -#define __VCGLIB_TETRAAPPEND - -#ifndef __VCG_TETRA_MESH -#error "This file should not be included alone. It is automatically included by complex.h" -#endif - -namespace vcg { -namespace tetra { -/** \ingroup trimesh */ -/*! \brief Class to safely duplicate and append (portion of) meshes. - -Adding elements to a mesh, like faces and vertices can involve the reallocation of the vectors of the involved elements. -This class provide the only safe methods to add elements of a mesh to another one. -\sa \ref allocation -*/ -template -class Append -{ -public: - typedef typename MeshLeft::ScalarType ScalarLeft; - typedef typename MeshLeft::CoordType CoordLeft; - typedef typename MeshLeft::VertexType VertexLeft; - typedef typename MeshLeft::EdgeType EdgeLeft; - typedef typename MeshLeft::FaceType FaceLeft; - typedef typename MeshLeft::TetraType TetraLeft; -// typedef typename MeshLeft::HEdgeType HEdgeLeft; - typedef typename MeshLeft::VertexPointer VertexPointerLeft; - typedef typename MeshLeft::VertexIterator VertexIteratorLeft; - typedef typename MeshLeft::EdgeIterator EdgeIteratorLeft; -// typedef typename MeshLeft::HEdgeIterator HEdgeIteratorLeft; - typedef typename MeshLeft::FaceIterator FaceIteratorLeft; - typedef typename MeshLeft::TetraIterator TetraIteratorLeft; - typedef typename MeshLeft::TetraPointer TetraPointerLeft; - - - typedef typename ConstMeshRight::ScalarType ScalarRight; - typedef typename ConstMeshRight::CoordType CoordRight; - typedef typename ConstMeshRight::VertexType VertexRight; - typedef typename ConstMeshRight::EdgeType EdgeRight; -// typedef typename ConstMeshRight::HEdgeType HEdgeRight; - typedef typename ConstMeshRight::FaceType FaceRight; - typedef typename ConstMeshRight::VertexPointer VertexPointerRight; - typedef typename ConstMeshRight::VertexIterator VertexIteratorRight; - typedef typename ConstMeshRight::EdgeIterator EdgeIteratorRight; -// typedef typename ConstMeshRight::HEdgeIterator HEdgeIteratorRight; - typedef typename ConstMeshRight::FaceIterator FaceIteratorRight; - typedef typename ConstMeshRight::FacePointer FacePointerRight; - typedef typename ConstMeshRight::TetraType TetraTypeRight; - typedef typename ConstMeshRight::TetraPointer TetraPointerRight; - typedef typename ConstMeshRight::TetraIterator TetraIteratorRight; - - - struct Remap{ - static size_t InvalidIndex() { return std::numeric_limits::max(); } - std::vector vert,face,edge, /*hedge,*/ tetra; - }; - - static void ImportVertexAdj(MeshLeft &ml, ConstMeshRight &mr, VertexLeft &vl, VertexRight &vr, Remap &remap ){ - // Vertex to Edge Adj - if(HasVEAdjacency(ml) && HasVEAdjacency(mr) && vr.cVEp() != 0){ - size_t i = Index(mr,vr.cVEp()); - vl.VEp() = (i>ml.edge.size())? 0 : &ml.edge[remap.edge[i]]; - vl.VEi() = vr.VEi(); - } - - // Vertex to Face Adj - if(HasPerVertexVFAdjacency(ml) && HasPerVertexVFAdjacency(mr) && vr.cVFp() != 0 ){ - size_t i = Index(mr,vr.cVFp()); - vl.VFp() = (i>ml.face.size())? 0 :&ml.face[remap.face[i]]; - vl.VFi() = vr.VFi(); - } - - if (HasPerVertexVTAdjacency(ml) && HasPerVertexVTAdjacency(mr) && vr.cVTp() != 0) { - size_t i = Index(mr, vr.cVTp()); - vl.VTp() = (i > ml.tetra.size()) ? 0 : &ml.tetra[remap.tetra[i]]; - vl.VTi() = vt.VTi(); - } - // // Vertex to HEdge Adj - // if(HasVHAdjacency(ml) && HasVHAdjacency(mr) && vr.cVHp() != 0){ - // vl.VHp() = &ml.hedge[remap.hedge[Index(mr,vr.cVHp())]]; - // vl.VHi() = vr.VHi(); - // } - } - - static void ImportEdgeAdj(MeshLeft &ml, ConstMeshRight &mr, EdgeLeft &el, const EdgeRight &er, Remap &remap) - { - // Edge to Edge Adj - if(HasEEAdjacency(ml) && HasEEAdjacency(mr)) - for(unsigned int vi = 0; vi < 2; ++vi) - { - size_t idx = Index(mr,er.cEEp(vi)); - el.EEp(vi) = (idx>ml.edge.size())? 0 : &ml.edge[remap.edge[idx]]; - el.EEi(vi) = er.cEEi(vi); - } - - // Edge to Face Adj - if(HasEFAdjacency(ml) && HasEFAdjacency(mr)){ - size_t idx = Index(mr,er.cEFp()); - el.EFp() = (idx>ml.face.size())? 0 :&ml.face[remap.face[idx]]; - el.EFi() = er.cEFi(); - } - - // // Edge to HEdge Adj - // if(HasEHAdjacency(ml) && HasEHAdjacency(mr)) - // el.EHp() = &ml.hedge[remap.hedge[Index(mr,er.cEHp())]]; - } - - - static void ImportFaceAdj(MeshLeft &ml, ConstMeshRight &mr, FaceLeft &fl, const FaceRight &fr, Remap &remap ) - { - // Face to Edge Adj - if(HasFEAdjacency(ml) && HasFEAdjacency(mr)){ - assert(fl.VN() == fr.VN()); - for( int vi = 0; vi < fl.VN(); ++vi ){ - size_t idx = remap.edge[Index(mr,fr.cFEp(vi))]; - if(idx!=Remap::InvalidIndex()) - fl.FEp(vi) = &ml.edge[idx]; - } - } - - // Face to Face Adj - if(HasFFAdjacency(ml) && HasFFAdjacency(mr)){ - assert(fl.VN() == fr.VN()); - for( int vi = 0; vi < fl.VN(); ++vi ){ - size_t idx = remap.face[Index(mr,fr.cFFp(vi))]; - if(idx!=Remap::InvalidIndex()){ - fl.FFp(vi) = &ml.face[idx]; - fl.FFi(vi) = fr.cFFi(vi); - } - } - } - - // // Face to HEedge Adj - // if(HasFHAdjacency(ml) && HasFHAdjacency(mr)) - // fl.FHp() = &ml.hedge[remap.hedge[Index(mr,fr.cFHp())]]; - } - - static void ImportTetraAdj(MeshLeft & ml, ConstMeshRight & mr, TetraLeft & tl, const TetraTypeRight &tr, Remap &remap ) - { - // TT Adj - if(HasTTAdjacency(ml) && HasTTAdjacency(mr)){ - for( int vi = 0; vi < 4; ++vi ){ - size_t idx = remap.tetra[Index(mr,tr.cTTp(vi))]; - if(idx!=Remap::InvalidIndex()){ - tl.TTp(vi) = &ml.tetra[idx]; - tl.TTi(vi) = fr.cTTi(vi); - } - } - } - - // // Face to HEedge Adj - // if(HasFHAdjacency(ml) && HasFHAdjacency(mr)) - // fl.FHp() = &ml.hedge[remap.hedge[Index(mr,fr.cFHp())]]; - } - -// static void ImportHEdgeAdj(MeshLeft &ml, ConstMeshRight &mr, HEdgeLeft &hl, const HEdgeRight &hr, Remap &remap, bool /*sel*/ ){ -// // HEdge to Vertex Adj -// if(HasHVAdjacency(ml) && HasHVAdjacency(mr)) -// hl.HVp() = &ml.vert[remap.vert[Index(mr,hr.cHVp())]]; - -// // HEdge to Edge Adj -// if(HasHEAdjacency(ml) && HasHEAdjacency(mr)){ -// size_t idx = Index(mr,hr.cHEp()) ; -// hl.HEp() = (idx>ml.edge.size())? 0 : &ml.edge[remap.edge[idx]]; -// } - -// // HEdge to Face Adj -// if(HasHFAdjacency(ml) && HasHFAdjacency(mr)){ -// size_t idx = Index(mr,hr.cHFp()); -// hl.HFp() = (idx>ml.face.size())? 0 :&ml.face[remap.face[idx]]; -// } - - -// // HEdge to Opposite HEdge Adj -// if(HasHOppAdjacency(ml) && HasHOppAdjacency(mr)) -// hl.HOp() = &ml.hedge[remap.hedge[Index(mr,hr.cHOp())]]; - -// // HEdge to Next HEdge Adj -// if(HasHNextAdjacency(ml) && HasHNextAdjacency(mr)) -// hl.HNp() = &ml.hedge[remap.hedge[Index(mr,hr.cHNp())]]; - -// // HEdge to Next HEdge Adj -// if(HasHPrevAdjacency(ml) && HasHPrevAdjacency(mr)) -// hl.HPp() = &ml.hedge[remap.hedge[Index(mr,hr.cHPp())]]; -// } - -// Append Right Mesh to the Left Mesh -// Append::Mesh(ml, mr) is equivalent to ml += mr. -// Note MeshRigth could be costant... - /*! \brief %Append the second mesh to the first one. - - The first mesh is not destroyed and no attempt of avoid duplication of already present elements is done. - If requested only the selected elements are appended to the first one. - The second mesh is not changed at all (it could be constant) with the exception of the selection (see below note). - - \note If the the selection of the vertexes is not consistent with the face selection - the append could build faces referencing non existent vertices - so it is mandatory that the selection of the vertices reflects the loose selection - from edges and faces (e.g. if a face is selected then all its vertices must be selected). - - \note Attributes. This function will copy only those attributes that are present in both meshes. - Two attributes in different meshes are considered the same iff they have the same - name and the same type. This may be deceiving because they could in fact have - different semantic, but this is up to the developer. - If the left mesh has attributes that are not in the right mesh, their values for the elements - of the right mesh will be uninitialized - - */ - -//TODO: -static void Mesh(MeshLeft& ml, ConstMeshRight& mr, const bool selected = false, const bool adjFlag = false) -{ - // Note that if the the selection of the vertexes is not consistent with the face selection - // the append could build faces referencing non existent vertices - // so it is mandatory that the selection of the vertices reflects the loose selection - // from edges and faces (e.g. if a face is selected all its vertices must be selected). - // note the use of the parameter for preserving existing vertex selection. - if(selected) - { - assert(adjFlag == false || ml.IsEmpty()); // It is rather meaningless to partially copy adj relations. - tri::UpdateSelection::VertexFromEdgeLoose(mr,true); - tri::UpdateSelection::VertexFromFaceLoose(mr,true); - } - - // phase 1. allocate on ml vert,edge,face, hedge to accomodat those of mr - // and build the remapping for all - - Remap remap; - - // vertex - remap.vert.resize(mr.vert.size(), Remap::InvalidIndex()); - VertexIteratorLeft vp; - size_t svn = UpdateSelection::VertexCount(mr); - if(selected) - vp=Allocator::AddVertices(ml,int(svn)); - else - vp=Allocator::AddVertices(ml,mr.vn); - - for(VertexIteratorRight vi=mr.vert.begin(); vi!=mr.vert.end(); ++vi) - { - if(!(*vi).IsD() && (!selected || (*vi).IsS())) - { - size_t ind=Index(mr,*vi); - remap.vert[ind]=int(Index(ml,*vp)); - ++vp; - } - } - // edge - remap.edge.resize(mr.edge.size(), Remap::InvalidIndex()); - EdgeIteratorLeft ep; - size_t sen = UpdateSelection::EdgeCount(mr); - if(selected) ep=Allocator::AddEdges(ml,sen); - else ep=Allocator::AddEdges(ml,mr.en); - - for(EdgeIteratorRight ei=mr.edge.begin(); ei!=mr.edge.end(); ++ei) - if(!(*ei).IsD() && (!selected || (*ei).IsS())){ - size_t ind=Index(mr,*ei); - remap.edge[ind]=int(Index(ml,*ep)); - ++ep; - } - - // face - remap.face.resize(mr.face.size(), Remap::InvalidIndex()); - FaceIteratorLeft fp; - size_t sfn = UpdateSelection::FaceCount(mr); - if(selected) fp=Allocator::AddFaces(ml,sfn); - else fp=Allocator::AddFaces(ml,mr.fn); - - for(FaceIteratorRight fi=mr.face.begin(); fi!=mr.face.end(); ++fi) - if(!(*fi).IsD() && (!selected || (*fi).IsS())){ - size_t ind=Index(mr,*fi); - remap.face[ind]=int(Index(ml,*fp)); - ++fp; - } - - // hedge - remap.hedge.resize(mr.hedge.size(),Remap::InvalidIndex()); - for(HEdgeIteratorRight hi=mr.hedge.begin(); hi!=mr.hedge.end(); ++hi) - if(!(*hi).IsD() && (!selected || (*hi).IsS())){ - size_t ind=Index(mr,*hi); - assert(remap.hedge[ind]==Remap::InvalidIndex()); - HEdgeIteratorLeft hp = Allocator::AddHEdges(ml,1); - (*hp).ImportData(*(hi)); - remap.hedge[ind]=Index(ml,*hp); - } - - // phase 2. - // copy data from ml to its corresponding elements in ml and adjacencies - - // vertex - for(VertexIteratorRight vi=mr.vert.begin();vi!=mr.vert.end();++vi) - if( !(*vi).IsD() && (!selected || (*vi).IsS())){ - ml.vert[remap.vert[Index(mr,*vi)]].ImportData(*vi); - if(adjFlag) ImportVertexAdj(ml,mr,ml.vert[remap.vert[Index(mr,*vi)]],*vi,remap); - } - - // edge - for(EdgeIteratorRight ei=mr.edge.begin();ei!=mr.edge.end();++ei) - if(!(*ei).IsD() && (!selected || (*ei).IsS())){ - ml.edge[remap.edge[Index(mr,*ei)]].ImportData(*ei); - // Edge to Vertex Adj - EdgeLeft &el = ml.edge[remap.edge[Index(mr,*ei)]]; - if(HasEVAdjacency(ml) && HasEVAdjacency(mr)){ - el.V(0) = &ml.vert[remap.vert[Index(mr,ei->cV(0))]]; - el.V(1) = &ml.vert[remap.vert[Index(mr,ei->cV(1))]]; - } - if(adjFlag) ImportEdgeAdj(ml,mr,el,*ei,remap); - } - - // face - const size_t textureOffset = ml.textures.size(); - bool WTFlag = HasPerWedgeTexCoord(mr) && (textureOffset>0); - for(FaceIteratorRight fi=mr.face.begin();fi!=mr.face.end();++fi) - if(!(*fi).IsD() && (!selected || (*fi).IsS())) - { - FaceLeft &fl = ml.face[remap.face[Index(mr,*fi)]]; - fl.Alloc(fi->VN()); - if(HasFVAdjacency(ml) && HasFVAdjacency(mr)){ - for(int i = 0; i < fl.VN(); ++i) - fl.V(i) = &ml.vert[remap.vert[Index(mr,fi->cV(i))]]; - } - fl.ImportData(*fi); - if(WTFlag) - for(int i = 0; i < fl.VN(); ++i) - fl.WT(i).n() += short(textureOffset); - if(adjFlag) ImportFaceAdj(ml,mr,ml.face[remap.face[Index(mr,*fi)]],*fi,remap); - - } - - // hedge - for(HEdgeIteratorRight hi=mr.hedge.begin();hi!=mr.hedge.end();++hi) - if(!(*hi).IsD() && (!selected || (*hi).IsS())){ - ml.hedge[remap.hedge[Index(mr,*hi)]].ImportData(*hi); - ImportHEdgeAdj(ml,mr,ml.hedge[remap.hedge[Index(mr,*hi)]],*hi,remap,selected); - } - - // phase 3. - // take care of other per mesh data: textures, attributes - - // At the end concatenate the vector with texture names. - ml.textures.insert(ml.textures.end(),mr.textures.begin(),mr.textures.end()); - - // Attributes. Copy only those attributes that are present in both meshes - // Two attributes in different meshes are considered the same if they have the same - // name and the same type. This may be deceiving because they could in fact have - // different semantic, but this is up to the developer. - // If the left mesh has attributes that are not in the right mesh, their values for the elements - // of the right mesh will be uninitialized - - unsigned int id_r; - typename std::set< PointerToAttribute >::iterator al, ar; - - // per vertex attributes - for(al = ml.vert_attr.begin(); al != ml.vert_attr.end(); ++al) - if(!(*al)._name.empty()){ - ar = mr.vert_attr.find(*al); - if(ar!= mr.vert_attr.end()){ - id_r = 0; - for(VertexIteratorRight vi=mr.vert.begin();vi!=mr.vert.end();++vi,++id_r) - if( !(*vi).IsD() && (!selected || (*vi).IsS())) - memcpy((*al)._handle->At(remap.vert[Index(mr,*vi)]),(*ar)._handle->At(id_r), - (*al)._handle->SizeOf()); - } - } - - // per edge attributes - for(al = ml.edge_attr.begin(); al != ml.edge_attr.end(); ++al) - if(!(*al)._name.empty()){ - ar = mr.edge_attr.find(*al); - if(ar!= mr.edge_attr.end()){ - id_r = 0; - for(EdgeIteratorRight ei=mr.edge.begin();ei!=mr.edge.end();++ei,++id_r) - if( !(*ei).IsD() && (!selected || (*ei).IsS())) - memcpy((*al)._handle->At(remap.edge[Index(mr,*ei)]),(*ar)._handle->At(id_r), - (*al)._handle->SizeOf()); - } - } - - // per face attributes - for(al = ml.face_attr.begin(); al != ml.face_attr.end(); ++al) - if(!(*al)._name.empty()){ - ar = mr.face_attr.find(*al); - if(ar!= mr.face_attr.end()){ - id_r = 0; - for(FaceIteratorRight fi=mr.face.begin();fi!=mr.face.end();++fi,++id_r) - if( !(*fi).IsD() && (!selected || (*fi).IsS())) - memcpy((*al)._handle->At(remap.face[Index(mr,*fi)]),(*ar)._handle->At(id_r), - (*al)._handle->SizeOf()); - } - } - - // per mesh attributes - // if both ml and mr have an attribute with the same name, no action is done - // if mr has an attribute that is NOT present in ml, the attribute is added to ml - //for(ar = mr.mesh_attr.begin(); ar != mr.mesh_attr.end(); ++ar) - // if(!(*ar)._name.empty()){ - // al = ml.mesh_attr.find(*ar); - // if(al== ml.mesh_attr.end()) - // //... - // } -} - -/*! \brief Copy the second mesh over the first one. - The first mesh is destroyed. If requested only the selected elements are copied. -*/ -static void MeshCopy(MeshLeft& ml, ConstMeshRight& mr, bool selected=false, const bool adjFlag = false) -{ - ml.Clear(); - Mesh(ml,mr,selected,adjFlag); - ml.bbox.Import(mr.bbox); -} -/*! \brief %Append only the selected elements of second mesh to the first one. - - It is just a wrap of the main Append::Mesh() - */ -static void Selected(MeshLeft& ml, ConstMeshRight& mr) -{ - Mesh(ml,mr,true); -} - -}; // end of class Append - - - - - -} // End Namespace tri -} // End Namespace vcg - - -#endif - - diff --git a/vcg/complex/tetrahedron/base.h b/vcg/complex/tetrahedron/base.h deleted file mode 100644 index c01c6c2b..00000000 --- a/vcg/complex/tetrahedron/base.h +++ /dev/null @@ -1,1065 +0,0 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004-2016 \/)\/ * -* 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_TETRA_MESH -#error "This file should not be included alone. It is automatically included by complex.h" -#endif -#ifndef __VCG_TETRA_COMPLEX_BASE -#define __VCG_TETRA_COMPLEX_BASE - -namespace vcg -{ - -//class PointerToAttribute -//{ -// public: -// SimpleTempDataBase *_handle; // pointer to the SimpleTempData that stores the attribute -// std::string _name; // name of the attribute -// int _sizeof; // size of the attribute type (used only with VMI loading) -// int _padding; // padding (used only with VMI loading) - -// int n_attr; // unique ID of the attribute -// std::type_index _type; -// void Resize(size_t sz) { ((SimpleTempDataBase *)_handle)->Resize(sz); } -// void Reorder(std::vector &newVertIndex) { ((SimpleTempDataBase *)_handle)->Reorder(newVertIndex); } -// bool operator<(const PointerToAttribute b) const { return (_name.empty() && b._name.empty()) ? (_handle < b._handle) : (_name < b._name); } - -// PointerToAttribute() : _type(typeid(void)){}; -//}; - -namespace tetra -{ -/** \addtogroup TetraMesh */ -/*@{*/ - -/* MeshTypeHolder is a class which is used to define the types in the mesh -*/ - -template -struct BaseMeshTypeHolder -{ - - typedef bool ScalarType; - typedef std::vector CONTV; - typedef std::vector CONTE; - typedef std::vector CONTF; - typedef std::vector CONTT; - - typedef CONTV VertContainer; - typedef _Vertex VertexType; - typedef typename TYPESPOOL::VertexPointer VertexPointer; - typedef const typename TYPESPOOL::VertexPointer ConstVertexPointer; - typedef bool CoordType; - typedef typename CONTV::iterator VertexIterator; - typedef typename CONTV::const_iterator ConstVertexIterator; - - typedef CONTE EdgeContainer; - typedef typename CONTE::value_type EdgeType; - typedef typename TYPESPOOL::EdgePointer EdgePointer; - typedef typename CONTE::iterator EdgeIterator; - typedef typename CONTE::const_iterator ConstEdgeIterator; - - typedef CONTF FaceContainer; - typedef typename CONTF::value_type FaceType; - typedef typename CONTF::const_iterator ConstFaceIterator; - typedef typename CONTF::iterator FaceIterator; - typedef typename TYPESPOOL::FacePointer FacePointer; - typedef const typename TYPESPOOL::FacePointer ConstFacePointer; - - typedef CONTT TetraContainer; - typedef typename CONTT::value_type TetraType; - typedef typename TYPESPOOL::TetraPointer TetraPointer; - typedef const typename TYPESPOOL::TetraPointer ConstTetraPointer; - typedef typename CONTT::iterator TetraIterator; - typedef typename CONTT::const_iterator ConstTetraIterator; -}; - -template -struct MeshTypeHolder : public T -{ -}; - -template -struct MeshTypeHolder : public T -{ - typedef CONT VertContainer; - typedef typename VertContainer::value_type VertexType; - typedef VertexType *VertexPointer; - typedef const VertexType *ConstVertexPointer; - typedef typename VertexType::ScalarType ScalarType; - typedef typename VertexType::CoordType CoordType; - typedef typename VertContainer::iterator VertexIterator; - typedef typename VertContainer::const_iterator ConstVertexIterator; -}; - -template -struct MeshTypeHolder : public T -{ - typedef CONT EdgeContainer; - typedef typename EdgeContainer::value_type EdgeType; - typedef typename EdgeContainer::value_type *EdgePointer; - typedef typename EdgeContainer::iterator EdgeIterator; - typedef typename EdgeContainer::const_iterator ConstEdgeIterator; -}; - -template -struct MeshTypeHolder : public T -{ - typedef CONT FaceContainer; - typedef typename FaceContainer::value_type FaceType; - typedef typename FaceContainer::const_iterator ConstFaceIterator; - typedef typename FaceContainer::iterator FaceIterator; - typedef FaceType *FacePointer; - typedef const FaceType *ConstFacePointer; -}; - -template -struct MeshTypeHolder : public T -{ - typedef CONT TetraContainer; - typedef typename TetraContainer::value_type TetraType; - typedef TetraType *TetraPointer; - typedef const TetraType *ConstTetraPointer; - typedef typename TetraContainer::iterator TetraIterator; - typedef typename TetraContainer::const_iterator ConstTetraIterator; -}; - -template -struct Der : public MeshTypeHolder -{ -}; -struct DummyContainer -{ - struct value_type - { - typedef int IAm; - }; -}; -/** \brief The official \b mesh class - -As explained in \ref basic_concepts, this class is templated over a list of container of simplexes (like vertex, face, edges) - */ - -template -class TetraMesh - : public MArity4, Container0, Der, Container1, Der, Container2, Der, Container3, Der> -{ - public: - typedef typename TetraMesh::ScalarType ScalarType; - typedef typename TetraMesh::VertContainer VertContainer; - typedef typename TetraMesh::EdgeContainer EdgeContainer; - typedef typename TetraMesh::FaceContainer FaceContainer; - typedef typename TetraMesh::TetraContainer TetraContainer; - - // types for vertex - typedef typename TetraMesh::VertexType VertexType; - typedef typename TetraMesh::VertexPointer VertexPointer; - typedef typename TetraMesh::ConstVertexPointer ConstVertexPointer; - typedef typename TetraMesh::CoordType CoordType; - typedef typename TetraMesh::VertexIterator VertexIterator; - typedef typename TetraMesh::ConstVertexIterator ConstVertexIterator; - - // types for edge - typedef typename TetraMesh::EdgeType EdgeType; - typedef typename TetraMesh::EdgePointer EdgePointer; - typedef typename TetraMesh::EdgeIterator EdgeIterator; - typedef typename TetraMesh::ConstEdgeIterator ConstEdgeIterator; - - //types for face - typedef typename TetraMesh::FaceType FaceType; - typedef typename TetraMesh::ConstFaceIterator ConstFaceIterator; - typedef typename TetraMesh::FaceIterator FaceIterator; - typedef typename TetraMesh::FacePointer FacePointer; - typedef typename TetraMesh::ConstFacePointer ConstFacePointer; - - // types for hedge - typedef typename TetraMesh::TetraType TetraType; - typedef typename TetraMesh::TetraPointer TetraPointer; - typedef typename TetraMesh::ConstTetraPointer ConstTetraPointer; - typedef typename TetraMesh::TetraIterator TetraIterator; - typedef typename TetraMesh::ConstTetraIterator ConstTetraIterator; - - typedef vcg::PointerToAttribute PointerToAttribute; - - typedef TetraMesh MeshType; - - typedef Box3 BoxType; - - /// Container of vertices, usually a vector. - VertContainer vert; - /// Current number of vertices; this member is for internal use only. You should always use the VN() member - int vn; - /// Current number of vertices - inline int VN() const { return vn; } - - /// Container of edges, usually a vector. - EdgeContainer edge; - /// Current number of edges; this member is for internal use only. You should always use the EN() member - int en; - /// Current number of edges - inline int EN() const { return en; } - - /// Container of faces, usually a vector. - FaceContainer face; - /// Current number of faces; this member is for internal use only. You should always use the FN() member - int fn; - /// Current number of faces - inline int FN() const { return fn; } - - /// Container of tetras, usually a vector. - TetraContainer tetra; - /// Current number of tetras; this member is for internal use only. You should always use the TN() member - int tn; - /// Current number of tetras; - inline int TN() const { return tn; } - - /// Bounding box of the mesh - Box3 bbox; - - /// Nomi di textures - // - std::vector textures; - // - std::vector normalmaps; - - int attrn; // total numer of attribute created - - std::set vert_attr; - std::set edge_attr; - std::set face_attr; - std::set tetra_attr; - std::set mesh_attr; - - template - class AttributeHandle - { - public: - AttributeHandle() { _handle = (SimpleTempData *)NULL; } - AttributeHandle(void *ah, const int &n) : _handle((SimpleTempData *)ah), n_attr(n) {} - AttributeHandle operator=(const PointerToAttribute &pva) - { - _handle = (SimpleTempData *)pva._handle; - n_attr = pva.n_attr; - return (*this); - } - - //pointer to the SimpleTempData that stores the attribute - SimpleTempData *_handle; - - // its attribute number - int n_attr; - - // access function - template - ATTR_TYPE &operator[](const RefType &i) { return (*_handle)[i]; } - void resize(size_t /*size*/){}; - }; - - template - class PerVertexAttributeHandle : public AttributeHandle - { - public: - PerVertexAttributeHandle() : AttributeHandle() {} - PerVertexAttributeHandle(void *ah, const int &n) : AttributeHandle(ah, n) {} - }; - - template - class PerFaceAttributeHandle : public AttributeHandle - { - public: - PerFaceAttributeHandle() : AttributeHandle() {} - PerFaceAttributeHandle(void *ah, const int &n) : AttributeHandle(ah, n) {} - }; - - template - class PerEdgeAttributeHandle : public AttributeHandle - { - public: - PerEdgeAttributeHandle() : AttributeHandle() {} - PerEdgeAttributeHandle(void *ah, const int &n) : AttributeHandle(ah, n) {} - }; - - template - class PerTetraAttributeHandle : public AttributeHandle - { - public: - PerTetraAttributeHandle() : AttributeHandle() {} - PerTetraAttributeHandle(void *ah, const int &n) : AttributeHandle(ah, n) {} - }; - - - template - class PerMeshAttributeHandle - { - public: - PerMeshAttributeHandle() { _handle = NULL; } - PerMeshAttributeHandle(void *ah, const int &n) : _handle((Attribute *)ah), n_attr(n) {} - PerMeshAttributeHandle operator=(const PerMeshAttributeHandle &pva) - { - _handle = (Attribute *)pva._handle; - n_attr = pva.n_attr; - return (*this); - } - - Attribute *_handle; - int n_attr; - ATTR_TYPE &operator()() { return *((Attribute *)_handle)->attribute; } - }; - - // Some common Handle typedefs to simplify use - typedef typename MeshType::template PerVertexAttributeHandle PerVertexScalarHandle; - typedef typename MeshType::template PerVertexAttributeHandle PerVertexIntHandle; - typedef typename MeshType::template PerVertexAttributeHandle PerVertexBoolHandle; - typedef typename MeshType::template PerVertexAttributeHandle PerVertexCoordHandle; - - typedef typename MeshType::template PerFaceAttributeHandle PerFaceScalarHandle; - typedef typename MeshType::template PerFaceAttributeHandle PerFaceIntHandle; - typedef typename MeshType::template PerFaceAttributeHandle PerFaceBoolHandle; - typedef typename MeshType::template PerFaceAttributeHandle PerFaceCoordHandle; - - typedef typename MeshType::template PerTetraAttributeHandle PerTetraScalarHandle; - typedef typename MeshType::template PerTetraAttributeHandle PerTetraIntHandle; - typedef typename MeshType::template PerTetraAttributeHandle PerTetraBoolHandle; - typedef typename MeshType::template PerTetraAttributeHandle PerTetraCoordHandle; - - // the camera member (that should keep the intrinsics) is no more needed since 2006, when intrisncs moved into the Shot structure - //Camera camera; // intrinsic - Shot shot; // intrinsic && extrinsic - - private: - /// The per-mesh color. Not very useful and meaningful... - Color4b c; - - public: - inline const Color4b &C() const { return c; } - inline Color4b &C() { return c; } - inline Color4b cC() const { return c; } - - /// Default constructor - TetraMesh() - { - Clear(); - } - - /// destructor - ~TetraMesh() - { - Clear(); - } - - int Mem(const int &nv, const int &nf, const int &nt) const - { - typename std::set::const_iterator i; - int size = 0; - size += sizeof(TetraMesh) + sizeof(VertexType) * nv + sizeof(FaceType) * nf + sizeof(TetraType) * nt; - - for (i = vert_attr.begin(); i != vert_attr.end(); ++i) - size += ((SimpleTempDataBase *)(*i)._handle)->SizeOf() * nv; - for (i = edge_attr.begin(); i != edge_attr.end(); ++i) - size += ((SimpleTempDataBase *)(*i)._handle)->SizeOf() * en; - for (i = face_attr.begin(); i != face_attr.end(); ++i) - size += ((SimpleTempDataBase *)(*i)._handle)->SizeOf() * nf; - for (i = tetra_attr.begin(); i != tetra_attr.end(); ++i) - size += ((SimpleTempDataBase *)(*i)._handle)->SizeOf() * nt; - for (i = mesh_attr.begin(); i != mesh_attr.end(); ++i) - size += ((SimpleTempDataBase *)(*i)._handle)->SizeOf(); - - return size; - } - int MemUsed() const { return Mem(vert.size(), face.size(), tetra.size()); } - inline int MemNeeded() const { return Mem(vn, fn, tn); } - - /// Function to destroy the mesh - void Clear() - { - for (FaceIterator fi = face.begin(); fi != face.end(); ++fi) - (*fi).Dealloc(); - vert.clear(); - face.clear(); - edge.clear(); - tetra.clear(); - // textures.clear(); - // normalmaps.clear(); - vn = 0; - en = 0; - fn = 0; - tn = 0; -// hn = 0; - imark = 0; - C() = Color4b::Gray; - } - - void ClearAttributes() - { - // Clear attributes - typename std::set::iterator i; - for (i = vert_attr.begin(); i != vert_attr.end(); ++i) - delete ((SimpleTempDataBase *)(*i)._handle); - vert_attr.clear(); - - for (i = edge_attr.begin(); i != edge_attr.end(); ++i) - delete ((SimpleTempDataBase *)(*i)._handle); - edge_attr.clear(); - - for (i = face_attr.begin(); i != face_attr.end(); ++i) - delete ((SimpleTempDataBase *)(*i)._handle); - face_attr.clear(); - - for (i = tetra_attr.begin(); i != tetra_attr.end(); ++i) - delete ((SimpleTempDataBase *)(*i)._handle); - tetra_attr.clear(); - - for (i = mesh_attr.begin(); i != mesh_attr.end(); ++i) - delete ((SimpleTempDataBase *)(*i)._handle); - mesh_attr.clear(); - attrn = 0; - } - - bool IsEmpty() const - { - return vert.empty() && edge.empty() && face.empty() && tetra.empty(); - } - - int &TetraNumber() { return tn; } - int &SimplexNumber() { return fn; } - int &VertexNumber() { return vn; } - - /// The incremental mark - int imark; - - private: - // TetraMesh cannot be copied. Use Append (see vcg/complex/append.h) - TetraMesh operator=(const TetraMesh & /*m*/) - { - assert(0); - return TetraMesh(); - } - TetraMesh(const TetraMesh &) {} - -}; // end class Mesh - -/// Initialize the imark-system of the faces -template -inline void InitFaceIMark(MeshType &m) -{ - typename MeshType::FaceIterator f; - - for (f = m.face.begin(); f != m.face.end(); ++f) - if (!(*f).IsD() && (*f).IsR() && (*f).IsW()) - (*f).InitIMark(); -} - -/// Initialize the imark-system of the vertices -template -inline void InitVertexIMark(MeshType &m) -{ - typename MeshType::VertexIterator vi; - - for (vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if (!(*vi).IsD() && (*vi).IsRW()) - (*vi).InitIMark(); -} - -///initialize the imark-sysyem of the tetras -template -inline void InitTetraIMark(MeshType &m) -{ - typename MeshType::TetraIterator ti; - - for (ti = m.tetra.begin(); ti != m.tetra.end(); ++ti) - if (!(*ti).IsD() && (*ti).IsRW()) - (*ti).InitIMark(); -} -/** \brief Access function to the incremental mark. - You should not use this member directly. In most of the case just use IsMarked() and Mark() -*/ -template -inline int &IMark(MeshType &m) { return m.imark; } - -/** \brief Check if the vertex incremental mark matches the one of the mesh. - @param m the mesh containing the element - @param v Vertex pointer */ -template -inline bool IsMarked(MeshType &m, typename MeshType::ConstVertexPointer v) { return v->cIMark() == m.imark; } - -/** \brief Check if the face incremental mark matches the one of the mesh. - @param m the mesh containing the element - @param f Face pointer */ -template -inline bool IsMarked(MeshType &m, typename MeshType::ConstFacePointer f) { return f->cIMark() == m.imark; } - -/** \brief Check if the tetra incremental mark matches the one of the mesh. - @param m the mesh containing the element - @param t tetra pointer */ -template -inline bool IsMarked(MeshType &m, typename MeshType::ConstTetraPointer t) { return t->cIMark() == m.imark; } - -/** \brief Set the vertex incremental mark of the vertex to the one of the mesh. - @param m the mesh containing the element - @param v Vertex pointer */ -template -inline void Mark(MeshType &m, typename MeshType::VertexPointer v) { v->IMark() = m.imark; } - -/** \brief Set the face incremental mark of the vertex to the one of the mesh. - @param m the mesh containing the element - @param f Vertex pointer */ -template -inline void Mark(MeshType &m, typename MeshType::FacePointer f) { f->IMark() = m.imark; } - -/** \brief Set the tetra incremental mark to the one of the mesh. - @param m the mesh containing the element - @param t tetra pointer */ -template -inline void Mark(MeshType &m, typename MeshType::TetraPointer t) { t->IMark() = m.imark; } - -/** \brief Unmark, in constant time, all the elements (face and vertices) of a mesh. - @param m the mesh containing the element - - In practice this function just increment the internal counter that stores the value for which an element is considered marked; - therefore all the mesh elements become immediately un-mmarked. - */ -template -inline void UnMarkAll(MeshType &m) -{ - ++m.imark; -} - -//template < class CType0, class CType1 , class CType2, class CType3> -//bool HasPerVertexVEAdjacency (const TetraMesh < CType0, CType1, CType2, CType3> & /*m*/) {return TetraMesh < CType0 , CType1, CType2, CType3>::VertContainer::value_type::HasVEAdjacency();} -//template < class CType0, class CType1, class CType2 , class CType3> -//bool HasPerEdgeVEAdjacency (const TetraMesh < CType0, CType1, CType2, CType3> & /*m*/) {return TetraMesh < CType0 , CType1, CType2, CType3>::EdgeContainer::value_type::HasVEAdjacency();} - -//TODO: ADD FT ET ADJACENCY -template -bool VertexVectorHasVFAdjacency(const std::vector &) { return VertexType::HasVFAdjacency(); } -template -bool VertexVectorHasVEAdjacency(const std::vector &) { return VertexType::HasVEAdjacency(); } -template -bool VertexVectorHasVTAdjacency(const std::vector &) { return VertexType::HasVTAdjacency(); } -template -bool EdgeVectorHasVEAdjacency(const std::vector &) { return EdgeType::HasVEAdjacency(); } -template -bool EdgeVectorHasEEAdjacency(const std::vector &) { return EdgeType::HasEEAdjacency(); } -template -bool FaceVectorHasVFAdjacency(const std::vector &) { return FaceType::HasVFAdjacency(); } - -template -bool HasPerVertexVFAdjacency(const TetraMeshType &m) { return tetra::VertexVectorHasVFAdjacency(m.vert); } -template -bool HasPerVertexVEAdjacency(const TetraMeshType &m) { return tetra::VertexVectorHasVEAdjacency(m.vert); } -template -bool HasPerVertexVTAdjacency(const TetraMeshType &m) { return tetra::VertexVectorHasVTAdjacency(m.vert); } -template -bool HasPerEdgeVEAdjacency(const TetraMeshType &m) { return tetra::EdgeVectorHasVEAdjacency(m.edge); } -template -bool HasPerFaceVFAdjacency(const TetraMeshType &m) { return tetra::FaceVectorHasVFAdjacency(m.face); } - -template -bool VertexVectorHasPerVertexQuality(const std::vector &) { return VertexType::HasQuality(); } -template -bool VertexVectorHasPerVertexNormal(const std::vector &) { return VertexType::HasNormal(); } -template -bool VertexVectorHasPerVertexColor(const std::vector &) { return VertexType::HasColor(); } -template -bool VertexVectorHasPerVertexMark(const std::vector &) { return VertexType::HasMark(); } -template -bool VertexVectorHasPerVertexFlags(const std::vector &) { return VertexType::HasFlags(); } -template -bool VertexVectorHasPerVertexRadius(const std::vector &) { return VertexType::HasRadius(); } -template -bool VertexVectorHasPerVertexCurvature(const std::vector &) { return VertexType::HasCurvature(); } -template -bool VertexVectorHasPerVertexCurvatureDir(const std::vector &) { return VertexType::HasCurvatureDir(); } -template -bool VertexVectorHasPerVertexTexCoord(const std::vector &) { return VertexType::HasTexCoord(); } - -template -bool HasPerVertexQuality(const TetraMeshType &m) { return tetra::VertexVectorHasPerVertexQuality(m.vert); } -template -bool HasPerVertexNormal(const TetraMeshType &m) { return tetra::VertexVectorHasPerVertexNormal(m.vert); } -template -bool HasPerVertexColor(const TetraMeshType &m) { return tetra::VertexVectorHasPerVertexColor(m.vert); } -template -bool HasPerVertexMark(const TetraMeshType &m) { return tetra::VertexVectorHasPerVertexMark(m.vert); } -template -bool HasPerVertexFlags(const TetraMeshType &m) { return tetra::VertexVectorHasPerVertexFlags(m.vert); } -template -bool HasPerVertexRadius(const TetraMeshType &m) { return tetra::VertexVectorHasPerVertexRadius(m.vert); } -template -bool HasPerVertexCurvature(const TetraMeshType &m) { return tetra::VertexVectorHasPerVertexCurvature(m.vert); } -template -bool HasPerVertexCurvatureDir(const TetraMeshType &m) { return tetra::VertexVectorHasPerVertexCurvatureDir(m.vert); } -template -bool HasPerVertexTexCoord(const TetraMeshType &m) { return tetra::VertexVectorHasPerVertexTexCoord(m.vert); } - -template -bool EdgeVectorHasPerEdgeQuality(const std::vector &) { return EdgeType::HasQuality(); } -template -bool EdgeVectorHasPerEdgeNormal(const std::vector &) { return EdgeType::HasNormal(); } -template -bool EdgeVectorHasPerEdgeColor(const std::vector &) { return EdgeType::HasColor(); } -template -bool EdgeVectorHasPerEdgeMark(const std::vector &) { return EdgeType::HasMark(); } -template -bool EdgeVectorHasPerEdgeFlags(const std::vector &) { return EdgeType::HasFlags(); } - -template -bool HasPerEdgeQuality(const TetraMeshType &m) { return tetra::EdgeVectorHasPerEdgeQuality(m.edge); } -template -bool HasPerEdgeNormal(const TetraMeshType &m) { return tetra::EdgeVectorHasPerEdgeNormal(m.edge); } -template -bool HasPerEdgeColor(const TetraMeshType &m) { return tetra::EdgeVectorHasPerEdgeColor(m.edge); } -template -bool HasPerEdgeMark(const TetraMeshType &m) { return tetra::EdgeVectorHasPerEdgeMark(m.edge); } -template -bool HasPerEdgeFlags(const TetraMeshType &m) { return tetra::EdgeVectorHasPerEdgeFlags(m.edge); } - -template -bool FaceVectorHasPerWedgeColor(const std::vector &) { return FaceType::HasWedgeColor(); } -template -bool FaceVectorHasPerWedgeNormal(const std::vector &) { return FaceType::HasWedgeNormal(); } -template -bool FaceVectorHasPerWedgeTexCoord(const std::vector &) { return FaceType::HasWedgeTexCoord(); } - -template -bool HasPerWedgeColor(const TetraMeshType &m) { return tetra::FaceVectorHasPerWedgeColor(m.face); } -template -bool HasPerWedgeNormal(const TetraMeshType &m) { return tetra::FaceVectorHasPerWedgeNormal(m.face); } -template -bool HasPerWedgeTexCoord(const TetraMeshType &m) { return tetra::FaceVectorHasPerWedgeTexCoord(m.face); } - -// template -// bool HasPolyInfo(const TetraMesh & /*m*/) { return TetraMesh::FaceContainer::value_type::HasPolyInfo(); } - -template -bool FaceVectorHasPerFaceFlags(const std::vector &) { return FaceType::HasFlags(); } -template -bool FaceVectorHasPerFaceNormal(const std::vector &) { return FaceType::HasNormal(); } -template -bool FaceVectorHasPerFaceColor(const std::vector &) { return FaceType::HasColor(); } -template -bool FaceVectorHasPerFaceMark(const std::vector &) { return FaceType::HasMark(); } -template -bool FaceVectorHasPerFaceQuality(const std::vector &) { return FaceType::HasQuality(); } -template -bool FaceVectorHasFFAdjacency(const std::vector &) { return FaceType::HasFFAdjacency(); } -template -bool FaceVectorHasFEAdjacency(const std::vector &) { return FaceType::HasFEAdjacency(); } -template -bool FaceVectorHasFVAdjacency(const std::vector &) { return FaceType::HasFVAdjacency(); } -template -bool FaceVectorHasPerFaceCurvatureDir(const std::vector &) { return FaceType::HasCurvatureDir(); } - -template -bool HasPerFaceFlags(const TetraMeshType &m) { return tetra::FaceVectorHasPerFaceFlags(m.face); } -template -bool HasPerFaceNormal(const TetraMeshType &m) { return tetra::FaceVectorHasPerFaceNormal(m.face); } -template -bool HasPerFaceColor(const TetraMeshType &m) { return tetra::FaceVectorHasPerFaceColor(m.face); } -template -bool HasPerFaceMark(const TetraMeshType &m) { return tetra::FaceVectorHasPerFaceMark(m.face); } -template -bool HasPerFaceQuality(const TetraMeshType &m) { return tetra::FaceVectorHasPerFaceQuality(m.face); } -template -bool HasPerFaceCurvatureDir(const TetraMeshType &m) { return tetra::FaceVectorHasPerFaceCurvatureDir(m.face); } -template -bool HasFFAdjacency(const TetraMeshType &m) { return tetra::FaceVectorHasFFAdjacency(m.face); } -template -bool HasEEAdjacency(const TetraMeshType &m) { return tetra::EdgeVectorHasEEAdjacency(m.edge); } -template -bool HasFEAdjacency(const TetraMeshType &m) { return tetra::FaceVectorHasFEAdjacency(m.face); } -template -bool HasFVAdjacency(const TetraMeshType &m) { return tetra::FaceVectorHasFVAdjacency(m.face); } - -//:::::::::::TETRA:::::::::::::::: -template -bool TetraVectorHasVTAdjacency(const std::vector &) { return TetraType::HasVTAdjacency(); } -template -bool TetraVectorHasTTAdjacency(const std::vector &) { return TetraType::HasTTAdjacency(); } - -template -bool HasTVAdjacency(const TetraMeshType &m) { return tetra::TetraVectorHasVTAdjacency(m.tetra); } -template -bool HasVFAdjacency(const TetraMeshType &m) { return tetra::FaceVectorHasVFAdjacency(m.face) && tetra::VertexVectorHasVFAdjacency(m.vert); } -template -bool HasVEAdjacency(const TetraMeshType &m) { return tetra::EdgeVectorHasVEAdjacency(m.edge) && tetra::VertexVectorHasVEAdjacency(m.vert); } -template -bool HasVTAdjacency(const TetraMeshType &m) { return tetra::VertexVectorHasVTAdjacency(m.vert) && tetra::TetraVectorHasVTAdjacency(m.tetra); } -template -bool HasTTAdjacency(const TetraMeshType &m) { return tetra::TetraVectorHasTTAdjacency(m.tetra); } -//template < class CType0, class CType1, class CType2 , class CType3> -//bool HasVEAdjacency (const TetraMesh < CType0, CType1, CType2, CType3> & /*m*/) {return TetraMesh < CType0 , CType1, CType2, CType3>::VertContainer::value_type::HasVEAdjacency();} - -// template -// bool HasVHAdjacency(const TetraMesh & /*m*/) { return TetraMesh::VertContainer::value_type::HasVHAdjacency(); } - -template -bool HasEVAdjacency(const TetraMesh & /*m*/) { return TetraMesh::EdgeType::HasEVAdjacency(); } - -//template < class CType0, class CType1, class CType2 , class CType3> -//bool HasEEAdjacency (const TetraMesh < CType0, CType1, CType2, CType3> & /*m*/) {return TetraMesh < CType0 , CType1, CType2, CType3>::EdgeType::HasEEAdjacency();} - -template -bool HasEFAdjacency(const TetraMesh & /*m*/) { return TetraMesh::EdgeType::HasEFAdjacency(); } - -// template -// bool HasEHAdjacency(const TetraMesh & /*m*/) { return TetraMesh::EdgeType::HasEHAdjacency(); } - -// template -// bool HasFHAdjacency(const TetraMesh & /*m*/) { return TetraMesh::FaceType::HasFHAdjacency(); } - -// template -// bool HasHVAdjacency(const TetraMesh & /*m*/) { return TetraMesh::HEdgeType::HasHVAdjacency(); } - -// template -// bool HasHEAdjacency(const TetraMesh & /*m*/) { return TetraMesh::HEdgeType::HasHEAdjacency(); } - -// template -// bool HasHFAdjacency(const TetraMesh & /*m*/) { return TetraMesh::HEdgeType::HasHFAdjacency(); } - -// template -// bool HasHNextAdjacency(const TetraMesh & /*m*/) { return TetraMesh::HEdgeType::HasHNextAdjacency(); } - -// template -// bool HasHPrevAdjacency(const TetraMesh & /*m*/) { return TetraMesh::HEdgeType::HasHPrevAdjacency(); } - -// template -// bool HasHOppAdjacency(const TetraMesh & /*m*/) { return TetraMesh::HEdgeType::HasHOppAdjacency(); } - -// //template < class CType0, class CType1 , class CType2, class CType3> -//bool HasVFAdjacency (const TetraMesh < CType0 , CType1, CType2, CType3> & m ) { -// // gcc 4.4: if the expressions assigned to a1 and a2 are replaced in the assert we get a compilation error -// // for the macro assert -// bool a1 = TetraMesh < CType0 , CType1, CType2, CType3>::FaceContainer::value_type::HasVFAdjacency(); -// bool a2 = TetraMesh < CType0 , CType1, CType2, CType3>::VertContainer::value_type::HasVFAdjacency(); -// // a1 and a2 are still evaluated but not referenced, this causes a warning -// (void)a1; -// (void)a2; -// assert(a1==a2); -// -// return vcg::tetra::HasPerVertexVFAdjacency< CType0, CType1 , CType2, CType3>(m) && -// vcg::tetra::HasPerFaceVFAdjacency< CType0, CType1 , CType2, CType3>(m) ; -//} - -template -bool HasPerVertexAttribute(const MeshType &m, std::string name) -{ - typename std::set::const_iterator ai; - typename MeshType::PointerToAttribute h; - h._name = name; - ai = m.vert_attr.find(h); - return (ai != m.vert_attr.end()); -} -template -bool HasPerFaceAttribute(const MeshType &m, std::string name) -{ - typename std::set::const_iterator ai; - typename MeshType::PointerToAttribute h; - h._name = name; - ai = m.face_attr.find(h); - return (ai != m.face_attr.end()); -} - -template -bool HasPerTetraAttribute(const MeshType &m, std::string name) -{ - typename std::set::const_iterator ai; - typename MeshType::PointerToAttribute h; - h._name = name; - ai = m.tetra_attr.find(h); - return (ai != m.tetra_attr.end()); -} - -template -bool HasPerMeshAttribute(const MeshType &m, std::string name) -{ - typename std::set::const_iterator ai; - typename MeshType::PointerToAttribute h; - h._name = name; - ai = m.mesh_attr.find(h); - return (ai != m.mesh_attr.end()); -} - -template -void RequireVertexCompactness(MeshType &m) -{ - if (m.vert.size() != size_t(m.vn)) - throw vcg::MissingCompactnessException("Vertex Vector Contains deleted elements"); -} -template -void RequireFaceCompactness(MeshType &m) -{ - if (m.face.size() != size_t(m.fn)) - throw vcg::MissingCompactnessException("Face Vector Contains deleted elements"); -} -template -void RequireEdgeCompactness(MeshType &m) -{ - if (m.edge.size() != size_t(m.en)) - throw vcg::MissingCompactnessException("Edge Vector Contains deleted elements"); -} - -template -void RequireTetraCompactness(MeshType &m) -{ - if (m.tetra.size() != size_t(m.tn)) - throw vcg::MissingCompactnessException("Tetra Vector Contains deleted elements"); -} - -template -void RequireCompactness(MeshType &m) -{ - RequireVertexCompactness(m); - RequireFaceCompactness(m); - RequireEdgeCompactness(m); - RequireTetraCompactness(m); -} - -template -void RequireTriangularMesh(MeshType &m) -{ - // if (tetra::HasPolyInfo(m)) - throw vcg::MissingTriangularRequirementException(""); -} -template -void RequirePolygonalMesh(MeshType &m) -{ - // if (!tetra::HasPolyInfo(m)) - throw vcg::MissingPolygonalRequirementException(""); -} - -template -void RequireVFAdjacency(MeshType &m) -{ - if (!tetra::HasVFAdjacency(m)) - throw vcg::MissingComponentException("VFAdjacency"); -} -template -void RequireVEAdjacency(MeshType &m) -{ - if (!tetra::HasVEAdjacency(m)) - throw vcg::MissingComponentException("VEAdjacency"); -} -template -void RequireFFAdjacency(MeshType &m) -{ - if (!tetra::HasFFAdjacency(m)) - throw vcg::MissingComponentException("FFAdjacency"); -} -template -void RequireEEAdjacency(MeshType &m) -{ - if (!tetra::HasEEAdjacency(m)) - throw vcg::MissingComponentException("EEAdjacency"); -} -template -void RequireFEAdjacency(MeshType &m) -{ - if (!tetra::HasFEAdjacency(m)) - throw vcg::MissingComponentException("FEAdjacency"); -} -template -void RequireVTAdjacency(MeshType &m) -{ - if (!tetra::HasVTAdjacency(m)) - throw vcg::MissingComponentException("VTAdjacency"); -} -// template -// void RequireFHAdjacency(MeshType &m) -// { -// if (!tetra::HasFHAdjacency(m)) -// throw vcg::MissingComponentException("FHAdjacency"); -// } - -template -void RequirePerVertexQuality(MeshType &m) -{ - if (!tetra::HasPerVertexQuality(m)) - throw vcg::MissingComponentException("PerVertexQuality "); -} -template -void RequirePerVertexNormal(MeshType &m) -{ - if (!tetra::HasPerVertexNormal(m)) - throw vcg::MissingComponentException("PerVertexNormal "); -} -template -void RequirePerVertexColor(MeshType &m) -{ - if (!tetra::HasPerVertexColor(m)) - throw vcg::MissingComponentException("PerVertexColor "); -} -template -void RequirePerVertexMark(MeshType &m) -{ - if (!tetra::HasPerVertexMark(m)) - throw vcg::MissingComponentException("PerVertexMark "); -} -template -void RequirePerVertexFlags(MeshType &m) -{ - if (!tetra::HasPerVertexFlags(m)) - throw vcg::MissingComponentException("PerVertexFlags "); -} -template -void RequirePerVertexRadius(MeshType &m) -{ - if (!tetra::HasPerVertexRadius(m)) - throw vcg::MissingComponentException("PerVertexRadius "); -} -template -void RequirePerVertexCurvature(MeshType &m) -{ - if (!tetra::HasPerVertexCurvature(m)) - throw vcg::MissingComponentException("PerVertexCurvature "); -} -template -void RequirePerVertexCurvatureDir(MeshType &m) -{ - if (!tetra::HasPerVertexCurvatureDir(m)) - throw vcg::MissingComponentException("PerVertexCurvatureDir"); -} -template -void RequirePerVertexTexCoord(MeshType &m) -{ - if (!tetra::HasPerVertexTexCoord(m)) - throw vcg::MissingComponentException("PerVertexTexCoord "); -} - -template -void RequirePerEdgeQuality(MeshType &m) -{ - if (!tetra::HasPerEdgeQuality(m)) - throw vcg::MissingComponentException("PerEdgeQuality "); -} -template -void RequirePerEdgeNormal(MeshType &m) -{ - if (!tetra::HasPerEdgeNormal(m)) - throw vcg::MissingComponentException("PerEdgeNormal "); -} -template -void RequirePerEdgeColor(MeshType &m) -{ - if (!tetra::HasPerEdgeColor(m)) - throw vcg::MissingComponentException("PerEdgeColor "); -} -template -void RequirePerEdgeMark(MeshType &m) -{ - if (!tetra::HasPerEdgeMark(m)) - throw vcg::MissingComponentException("PerEdgeMark "); -} -template -void RequirePerEdgeFlags(MeshType &m) -{ - if (!tetra::HasPerEdgeFlags(m)) - throw vcg::MissingComponentException("PerEdgeFlags "); -} - -template -void RequirePerFaceFlags(MeshType &m) -{ - if (!tetra::HasPerFaceFlags(m)) - throw vcg::MissingComponentException("PerFaceFlags "); -} -template -void RequirePerFaceNormal(MeshType &m) -{ - if (!tetra::HasPerFaceNormal(m)) - throw vcg::MissingComponentException("PerFaceNormal "); -} -template -void RequirePerFaceColor(MeshType &m) -{ - if (!tetra::HasPerFaceColor(m)) - throw vcg::MissingComponentException("PerFaceColor "); -} -template -void RequirePerFaceMark(MeshType &m) -{ - if (!tetra::HasPerFaceMark(m)) - throw vcg::MissingComponentException("PerFaceMark "); -} -template -void RequirePerFaceQuality(MeshType &m) -{ - if (!tetra::HasPerFaceQuality(m)) - throw vcg::MissingComponentException("PerFaceQuality "); -} -template -void RequirePerFaceCurvatureDir(MeshType &m) -{ - if (!tetra::HasPerFaceCurvatureDir(m)) - throw vcg::MissingComponentException("PerFaceCurvatureDir"); -} - -template -void RequirePerFaceWedgeColor(MeshType &m) -{ - if (!tetra::HasPerWedgeColor(m)) - throw vcg::MissingComponentException("PerFaceWedgeColor "); -} -template -void RequirePerFaceWedgeNormal(MeshType &m) -{ - if (!tetra::HasPerWedgeNormal(m)) - throw vcg::MissingComponentException("PerFaceWedgeNormal "); -} -template -void RequirePerFaceWedgeTexCoord(MeshType &m) -{ - if (!tetra::HasPerWedgeTexCoord(m)) - throw vcg::MissingComponentException("PerFaceWedgeTexCoord"); -} - -template -void RequirePerVertexAttribute(MeshType &m, const char *name) -{ - if (!HasPerVertexAttribute(m, name)) - throw vcg::MissingComponentException("PerVertex attribute"); -} -template -void RequirePerEdgeAttribute(MeshType &m, const char *name) -{ - if (!HasPerEdgeAttribute(m, name)) - throw vcg::MissingComponentException("PerEdge attribute"); -} -template -void RequirePerFaceAttribute(MeshType &m, const char *name) -{ - if (!HasPerFaceAttribute(m, name)) - throw vcg::MissingComponentException("PerFace attribute"); -} -template -void RequirePerMeshAttribute(MeshType &m, const char *name) -{ - if (!HasPerMeshAttribute(m, name)) - throw vcg::MissingComponentException("PerMesh attribute"); -} - -/*@}*/ -/*@}*/ -} // end namespace -} // end namespace - -#endif // BASE_H diff --git a/vcg/simplex/tetrahedron/component.h b/vcg/simplex/tetrahedron/component.h index 815f39c1..801de94e 100644 --- a/vcg/simplex/tetrahedron/component.h +++ b/vcg/simplex/tetrahedron/component.h @@ -81,8 +81,8 @@ public: static bool HasQuality() { return false; } static bool HasQuality3() { return false; } - bool IsQualityEnabled() const { return T::TetraType::HasQuality(); } - bool IsQuality3Enabled() const { return T::TetraType::HasQuality3(); } + inline bool IsQualityEnabled() const { return T::TetraType::HasQuality(); } + inline bool IsQuality3Enabled() const { return T::TetraType::HasQuality3(); } //Empty flags int &Flags() { static int dummyflags(0); assert(0); return dummyflags; } @@ -103,10 +103,10 @@ public: //Empty Adjacency typedef int VFAdjType; - typename T::TetraPointer & VTp( const int ) { static typename T::TetraPointer tp=0; assert(0); return tp; } + typename T::TetraPointer & VTp ( const int ) { static typename T::TetraPointer tp=0; assert(0); return tp; } typename T::TetraPointer const cVTp( const int ) const { static typename T::TetraPointer const tp=0; assert(0); return tp; } - typename T::TetraPointer & TTp( const int ) { static typename T::TetraPointer tp=0; assert(0); return tp; } + typename T::TetraPointer & TTp ( const int ) { static typename T::TetraPointer tp=0; assert(0); return tp; } typename T::TetraPointer const cTTp( const int ) const { static typename T::TetraPointer const tp=0; assert(0); return tp; } char & VTi( const int j ) { static char z=0; assert(0); return z; } @@ -122,8 +122,8 @@ public: } } - static bool HasVTAdjacency() { return false; } - static bool HasTTAdjacency() { return false; } + static bool HasVTAdjacency() { return false; } + static bool HasTTAdjacency() { return false; } static bool HasTTAdjacencyOcc() { return false; } static bool HasVTAdjacencyOcc() { return false; } @@ -154,20 +154,39 @@ public: v[1]=0; v[2]=0; v[3]=0; + +/******* vertex and faces indices scheme********* + * + * /2\` + * / \ ` + * / \ ` + * / \ _ 3` + * / _ \ ' + * / _ \ ' + * /0___________1\' + * + */ + findices[0][0] = 0; findices[0][1] = 1; findices[0][2] = 2; + findices[1][0] = 0; findices[1][1] = 3; findices[1][2] = 1; + findices[2][0] = 0; findices[2][1] = 2; findices[2][2] = 3; + findices[3][0] = 1; findices[3][1] = 3; findices[3][2] = 2; } - typedef typename T::VertexType::CoordType CoordType; - typedef typename T::VertexType::ScalarType ScalarType; + + typedef typename T::VertexType::CoordType CoordType; + typedef typename T::VertexType::ScalarType ScalarType; - inline typename T::VertexType * & V( const int j ) { assert(j>=0 && j<4); return v[j]; } - inline typename T::VertexType * const & V( const int j ) const { assert(j>=0 && j<4); return v[j]; } - inline typename T::VertexType * const cV( const int j ) const { assert(j>=0 && j<4); return v[j]; } + inline typename T::VertexType * & V( const int j ) { assert(j>=0 && j<4); return v[j]; } + inline typename T::VertexType * const & V( const int j ) const { assert(j>=0 && j<4); return v[j]; } + inline typename T::VertexType * const cV( const int j ) const { assert(j>=0 && j<4); return v[j]; } - // Shortcut per accedere ai punti delle facce - inline typename CoordType & P( const int j ) { assert(j>=0 && j<4); return v[j]->P(); } - inline const typename CoordType & P( const int j ) const { assert(j>=0 && j<4); return v[j]->cP(); } - inline const typename CoordType &cP( const int j ) const { assert(j>=0 && j<4); return v[j]->cP(); } + inline typename size_t const cFtoVi (const int f, const int j) const { assert(f >= 0 && f < 4); assert(j >= 0 && j < 3); return findices[f][j]; } - /** Return the pointer to the ((j+1)%3)-th vertex of the face. + // Shortcut for tetra points + inline typename CoordType & P( const int j ) { assert(j>=0 && j<4); return v[j]->P(); } + inline const typename CoordType & P( const int j ) const { assert(j>=0 && j<4); return v[j]->cP(); } + inline const typename CoordType &cP( const int j ) const { assert(j>=0 && j<4); return v[j]->cP(); } + + /** Return the pointer to the ((j+1)%4)-th vertex of the tetra. @param j Index of the face vertex. */ inline typename T::VertexType * & V0( const int j ) { return V(j);} @@ -184,18 +203,18 @@ public: inline const typename T::VertexType * const & cV3( const int j ) const { return cV((j+3)%4);} /// Shortcut to get vertex values - inline typename CoordType & P0( const int j ) { return V(j)->P();} - inline typename CoordType & P1( const int j ) { return V((j+1)%4)->P();} - inline typename CoordType & P2( const int j ) { return V((j+2)%4)->P();} - inline typename CoordType & P3( const int j ) { return V((j+3)%4)->P();} - inline const typename CoordType & P0( const int j ) const { return V(j)->P();} - inline const typename CoordType & P1( const int j ) const { return V((j+1)%4)->P();} - inline const typename CoordType & P2( const int j ) const { return V((j+2)%4)->P();} - inline const typename CoordType & P3( const int j ) const { return V((j+3)%4)->P();} - inline const typename CoordType & cP0( const int j ) const { return cV(j)->P();} - inline const typename CoordType & cP1( const int j ) const { return cV((j+1)%4)->P();} - inline const typename CoordType & cP2( const int j ) const { return cV((j+2)%4)->P();} - inline const typename CoordType & cP3( const int j ) const { return cV((j+3)%4)->P();} + inline typename CoordType &P0 (const int j) { return V(j)->P(); } + inline typename CoordType &P2 (const int j) { return V((j + 2) % 4)->P(); } + inline typename CoordType &P3 (const int j) { return V((j + 3) % 4)->P(); } + inline typename CoordType &P1 (const int j) { return V((j + 1) % 4)->P(); } + inline const typename CoordType &P0 (const int j) const { return V(j)->P(); } + inline const typename CoordType &P1 (const int j) const { return V((j + 1) % 4)->P(); } + inline const typename CoordType &P2 (const int j) const { return V((j + 2) % 4)->P(); } + inline const typename CoordType &P3 (const int j) const { return V((j + 3) % 4)->P(); } + inline const typename CoordType &cP0(const int j) const { return cV(j)->P(); } + inline const typename CoordType &cP1(const int j) const { return cV((j + 1) % 4)->P(); } + inline const typename CoordType &cP2(const int j) const { return cV((j + 2) % 4)->P(); } + inline const typename CoordType &cP3(const int j) const { return cV((j + 3) % 4)->P(); } static bool HasVertexRef() { return true; } static bool HasTVAdjacency() { return true; } @@ -207,6 +226,7 @@ public: private: typename T::VertexType *v[4]; + size_t findices[4][3]; }; diff --git a/vcg/complex/tetrahedron/complex.h b/vcg/simplex/tetrahedron/topology.h similarity index 58% rename from vcg/complex/tetrahedron/complex.h rename to vcg/simplex/tetrahedron/topology.h index 8a28cdfc..d1c02bcb 100644 --- a/vcg/complex/tetrahedron/complex.h +++ b/vcg/simplex/tetrahedron/topology.h @@ -21,48 +21,28 @@ * * ****************************************************************************/ -#ifndef __VCG_TETRA_MESH_H -#define __VCG_TETRA_MESH_H -#define __VCG_TETRA_MESH -#define __VCG_MESH +#ifndef _VCG_TETRA_TOPOLOGY +#define _VCG_TETRA_TOPOLOGY -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +namespace vcg { +namespace tetrahedron { +/** \addtogroup tetrahedron */ +/*@{*/ -#undef __VCG_TETRA_MESH -#undef __VCG_MESH +/** Return a boolean that indicate if the j-th face of the tetra is a border. + @param j Index of the face + @return true if j is an face of border, false otherwise +*/ +template +inline bool IsBorder(TetraType const & t, const int j ) +{ + if(TetraType::HasTTAdjacency()) + return t.cTTp(j)==&t; + assert(0); + return true; +} -#endif +} +} +#endif \ No newline at end of file diff --git a/vcg/simplex/vertex/component.h b/vcg/simplex/vertex/component.h index cf42f2fb..2e7ad78a 100644 --- a/vcg/simplex/vertex/component.h +++ b/vcg/simplex/vertex/component.h @@ -98,8 +98,16 @@ public: typename TT::TetraPointer &VTp() { static typename TT::TetraPointer tp = 0; assert(0); return tp; } typename TT::TetraPointer cVTp() const { static typename TT::TetraPointer tp = 0; assert(0); return tp; } - int &VTi() { static int z = 0; return z; } + int &VTi() { static int z = 0; assert(0); return z; } + int cVTi() const { static int z = 0; assert(0); return z; } static bool HasVTAdjacency() { return false; } + bool IsVTInitialized() const {return static_cast(this)->cVTi()!=-1;} + void VTClear() { + if(IsVTInitialized()) { + static_cast(this)->VTp()=0; + static_cast(this)->VTi()=-1; + } + } typename TT::FacePointer &VFp() { static typename TT::FacePointer fp=0; assert(0); return fp; } typename TT::FacePointer cVFp() const { static typename TT::FacePointer fp=0; assert(0); return fp; } @@ -589,6 +597,7 @@ public: typename T::TetraPointer &VTp() { return _tp; } typename T::TetraPointer cVTp() const { return _tp; } int &VTi() {return _zp; } + int cVTi() const { return _zp; } static bool HasVTAdjacency() { return true; } static void Name( std::vector< std::string > & name ) { name.push_back( std::string("VTAdj") ); T::Name(name); } diff --git a/vcg/space/tetra3.h b/vcg/space/tetra3.h index 0c023cab..eaa28d12 100644 --- a/vcg/space/tetra3.h +++ b/vcg/space/tetra3.h @@ -298,6 +298,27 @@ static int FofEE(const int &indexE0,const int &indexE1) return edgesface[indexE0][indexE1]; } + +// compute the barycenter +template +static Point3 Barycenter(const TetraType & t) +{ + return ((t.cP(0)+t.cP(1)+t.cP(2)+t.cP(3))/(TetraType::ScalarType) 4.0); +} + +// compute and return the volume of a tetrahedron + template +static typename TetraType::ScalarType ComputeVolume( const TetraType & t){ + return (typename TetraType::ScalarType)((( t.cP(2)-t.cP(0))^(t.cP(1)-t.cP(0) ))*(t.cP(3)-t.cP(0))/6.0); +} + +/// Returns the normal to the face face of the tetrahedron t +template +static Point3 Normal( const TetraType &t,const int & face) +{ + return(((t.cP(Tetra::VofF(face,1))-t.cP(Tetra::VofF(face,0)))^(t.cP(Tetra::VofF(face,2))-t.cP(Tetra::VofF(face,0)))).Normalize()); +} + }; /** @@ -488,25 +509,7 @@ ScalarType ComputeAspectRatio() }; //end Class -// compute the barycenter -template -Point3 Barycenter(const Tetra3 &t) -{ - return ((t.cP(0)+t.cP(1)+t.cP(2)+t.cP(3))/(ScalarType) 4.0); -} -// compute and return the volume of a tetrahedron - template -typename TetraType::ScalarType ComputeVolume( const TetraType & t){ - return (typename TetraType::ScalarType)((( t.cP(2)-t.cP(0))^(t.cP(1)-t.cP(0) ))*(t.cP(3)-t.cP(0))/6.0); -} - -/// Returns the normal to the face face of the tetrahedron t -template -Point3 Normal( const TetraType &t,const int &face) -{ - return(((t.cP(Tetra::VofF(face,1))-t.cP(Tetra::VofF(face,0)))^(t.cP(Tetra::VofF(face,2))-t.cP(Tetra::VofF(face,0)))).Normalize()); -} /*@}*/ } // end namespace diff --git a/wrap/io_tetramesh/export_ply.h b/wrap/io_tetramesh/export_ply.h index 120b6ba2..f897744d 100644 --- a/wrap/io_tetramesh/export_ply.h +++ b/wrap/io_tetramesh/export_ply.h @@ -403,6 +403,7 @@ public: vv[2]=indices[fp->cV(2)]; vv[3]=indices[fp->cV(3)]; + fwrite(&c,1,1,fpout); fwrite(vv,sizeof(int),4,fpout); @@ -432,6 +433,7 @@ public: } else // ***** ASCII ***** { + fprintf(fpout,"%d " , 4); fprintf(fpout,"%d %d %d %d ", indices[fp->cV(0)], indices[fp->cV(1)], indices[fp->cV(2)], indices[fp->cV(3)]);