Updated to reflect the Normal() -> TriangleNormal() change

Updated to reflect the changes to the UpdateFlags (new function names ::VertexBorderFromFaceAdj ::VertexBorderFromFaceBorder)
This commit is contained in:
Paolo Cignoni 2014-11-12 00:14:23 +00:00
parent 4b0e72293f
commit 9d89004760
8 changed files with 224 additions and 222 deletions

View File

@ -255,10 +255,10 @@ class Clustering
else else
Grid.siz = Point3i::Construct(Grid.dim / _cellsize); Grid.siz = Point3i::Construct(Grid.dim / _cellsize);
// find voxel size // find voxel size
Grid.voxel[0] = Grid.dim[0]/Grid.siz[0]; Grid.voxel[0] = Grid.dim[0]/Grid.siz[0];
Grid.voxel[1] = Grid.dim[1]/Grid.siz[1]; Grid.voxel[1] = Grid.dim[1]/Grid.siz[1];
Grid.voxel[2] = Grid.dim[2]/Grid.siz[2]; Grid.voxel[2] = Grid.dim[2]/Grid.siz[2];
} }
BasicGrid<ScalarType> Grid; BasicGrid<ScalarType> Grid;
@ -277,18 +277,18 @@ class Clustering
STDEXT::hash_map<HashedPoint3i,CellType> GridCell; STDEXT::hash_map<HashedPoint3i,CellType> GridCell;
void AddPointSet(MeshType &m, bool UseOnlySelected=false) void AddPointSet(MeshType &m, bool UseOnlySelected=false)
{ {
VertexIterator vi; VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) for(vi=m.vert.begin();vi!=m.vert.end();++vi)
if(!(*vi).IsD()) if(!(*vi).IsD())
if(!UseOnlySelected || (*vi).IsS()) if(!UseOnlySelected || (*vi).IsS())
{ {
HashedPoint3i pi; HashedPoint3i pi;
Grid.PToIP((*vi).cP(), pi ); Grid.PToIP((*vi).cP(), pi );
GridCell[pi].AddVertex(m,Grid,pi,*(vi)); GridCell[pi].AddVertex(m,Grid,pi,*(vi));
} }
} }
void AddMesh(MeshType &m) void AddMesh(MeshType &m)
{ {
@ -377,7 +377,7 @@ class Clustering
// the best orientation according to the averaged normal // the best orientation according to the averaged normal
if(!DuplicateFaceParam) if(!DuplicateFaceParam)
{ {
CoordType N=vcg::Normal(m.face[i]); CoordType N=TriangleNormal(m.face[i]);
int badOrient=0; int badOrient=0;
if( N.dot((*ti).v[0]->N()) <0) ++badOrient; if( N.dot((*ti).v[0]->N()) <0) ++badOrient;
if( N.dot((*ti).v[1]->N()) <0) ++badOrient; if( N.dot((*ti).v[1]->N()) <0) ++badOrient;

View File

@ -66,7 +66,7 @@ template <class MESH> class AdvancingFront {
UpdateFlags<MESH>::FaceBorderFromNone(mesh); UpdateFlags<MESH>::FaceBorderFromNone(mesh);
UpdateFlags<MESH>::VertexBorderFromFace(mesh); UpdateFlags<MESH>::VertexBorderFromFaceBorder(mesh);
nb.clear(); nb.clear();
nb.resize(mesh.vert.size(), 0); nb.resize(mesh.vert.size(), 0);
@ -343,7 +343,7 @@ public:
protected: protected:
void AddFace(int v0, int v1, int v2) { void AddFace(int v0, int v1, int v2) {
FaceIterator fi = vcg::tri::Allocator<MESH>::AddFace(mesh,v0,v1,v2); FaceIterator fi = vcg::tri::Allocator<MESH>::AddFace(mesh,v0,v1,v2);
ComputeNormalizedNormal(*fi); fi->N() = TriangleNormal(*fi).Normalize();
if(tri::HasVFAdjacency(mesh)) if(tri::HasVFAdjacency(mesh))
{ {
for(int j=0;j<3;++j) for(int j=0;j<3;++j)

View File

@ -376,7 +376,7 @@ void SphericalCap(MeshType &in, float angleRad, const int subdiv = 3 )
tri::Refine(in, MidPoint<MeshType>(&in)); tri::Refine(in, MidPoint<MeshType>(&in));
tri::UpdateFlags<MeshType>::FaceBorderFromFF(in); tri::UpdateFlags<MeshType>::FaceBorderFromFF(in);
tri::UpdateFlags<MeshType>::VertexBorderFromFace(in); tri::UpdateFlags<MeshType>::VertexBorderFromFaceBorder(in);
for(int i=0;i<in.vn;++i) for(int i=0;i<in.vn;++i)
if(in.vert[i].IsB()) if(in.vert[i].IsB())
@ -1015,6 +1015,7 @@ void BuildPrismFaceShell(MeshType &mIn, MeshType &mOut, float height=0, float in
typedef typename MeshType::CoordType CoordType; typedef typename MeshType::CoordType CoordType;
if(height==0) height = mIn.bbox.Diag()/100.0f; if(height==0) height = mIn.bbox.Diag()/100.0f;
if(inset==0) inset = mIn.bbox.Diag()/200.0f; if(inset==0) inset = mIn.bbox.Diag()/200.0f;
tri::UpdateTopology<MeshType>::FaceFace(mIn);
tri::UpdateFlags<MeshType>::FaceClearV(mIn); tri::UpdateFlags<MeshType>::FaceClearV(mIn);
for(size_t i=0;i<mIn.face.size();++i) if(!mIn.face[i].IsV()) for(size_t i=0;i<mIn.face.size();++i) if(!mIn.face[i].IsV())
{ {
@ -1065,6 +1066,7 @@ void BuildPrismFaceShell(MeshType &mIn, MeshType &mOut, float height=0, float in
if(smoothFlag) if(smoothFlag)
{ {
faceM.face.EnableFFAdjacency();
tri::UpdateTopology<MeshType>::FaceFace(faceM); tri::UpdateTopology<MeshType>::FaceFace(faceM);
tri::UpdateFlags<MeshType>::FaceBorderFromFF(faceM); tri::UpdateFlags<MeshType>::FaceBorderFromFF(faceM);
tri::Refine(faceM, MidPoint<MeshType>(&faceM),0,true); tri::Refine(faceM, MidPoint<MeshType>(&faceM),0,true);

View File

@ -94,7 +94,7 @@ public:
assert(e0.IsBorder()); assert(e0.IsBorder());
e1=e0; e1=e0;
e1.NextB(); e1.NextB();
n=vcg::Normal<TrivialEar>(*this); n=TriangleNormal<TrivialEar>(*this);
ComputeQuality(); ComputeQuality();
ComputeAngle(); ComputeAngle();
} }
@ -159,7 +159,7 @@ public:
(*f).V(0) = e0.VFlip(); (*f).V(0) = e0.VFlip();
(*f).V(1) = e0.v; (*f).V(1) = e0.v;
(*f).V(2) = e1.v; (*f).V(2) = e1.v;
face::ComputeNormalizedNormal(*f); f->N() = TriangleNormal(*f).Normalize();
face::FFAttachManifold(f,0,e0.f,e0.z); face::FFAttachManifold(f,0,e0.f,e0.z);
face::FFAttachManifold(f,1,e1.f,e1.z); face::FFAttachManifold(f,1,e1.f,e1.z);
@ -644,8 +644,8 @@ template<class EAR>
static float ComputeDihedralAngle(CoordType p1,CoordType p2,CoordType p3,CoordType p4) static float ComputeDihedralAngle(CoordType p1,CoordType p2,CoordType p3,CoordType p4)
{ {
CoordType n1 = NormalizedNormal(p1,p3,p2); CoordType n1 = Normal(p1,p3,p2);
CoordType n2 = NormalizedNormal(p1,p2,p4); CoordType n2 = Normal(p1,p2,p4);
return math::ToDeg(AngleN(n1,n2)); return math::ToDeg(AngleN(n1,n2));
} }

View File

@ -8,7 +8,7 @@
* \ * * \ *
* All rights reserved. * * All rights reserved. *
* * * *
* This program is free software; you can redistribute it and/or modify * * 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 * * it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or * * the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. * * (at your option) any later version. *
@ -89,40 +89,40 @@ namespace tri{
/** /**
This class describe Quadric based collapse operation. This class describe Quadric based collapse operation.
Requirements: Requirements:
Vertex Vertex
must have: must have:
incremental mark incremental mark
VF topology VF topology
must have: must have:
members members
QuadricType Qd(); QuadricType Qd();
ScalarType W() const; ScalarType W() const;
A per-vertex Weight that can be used in simplification A per-vertex Weight that can be used in simplification
lower weight means that error is lowered, lower weight means that error is lowered,
standard: return W==1.0 standard: return W==1.0
void Merge(MESH_TYPE::vertex_type const & v); void Merge(MESH_TYPE::vertex_type const & v);
Merges the attributes of the current vertex with the ones of v Merges the attributes of the current vertex with the ones of v
(e.g. its weight with the one of the given vertex, the color ect). (e.g. its weight with the one of the given vertex, the color ect).
Standard: void function; Standard: void function;
OtherWise the class should be templated with a static helper class that helps to retrieve these functions. OtherWise the class should be templated with a static helper class that helps to retrieve these functions.
If the vertex class exposes these functions a default static helper class is provided. If the vertex class exposes these functions a default static helper class is provided.
*/ */
//**Helper CLASSES**// //**Helper CLASSES**//
template <class VERTEX_TYPE> template <class VERTEX_TYPE>
class QInfoStandard class QInfoStandard
{ {
public: public:
QInfoStandard(){} QInfoStandard(){}
static void Init(){} static void Init(){}
static math::Quadric<double> &Qd(VERTEX_TYPE &v) {return v.Qd();} static math::Quadric<double> &Qd(VERTEX_TYPE &v) {return v.Qd();}
@ -130,7 +130,7 @@ namespace tri{
static typename VERTEX_TYPE::ScalarType W(VERTEX_TYPE */*v*/) {return 1.0;} static typename VERTEX_TYPE::ScalarType W(VERTEX_TYPE */*v*/) {return 1.0;}
static typename VERTEX_TYPE::ScalarType W(VERTEX_TYPE &/*v*/) {return 1.0;} static typename VERTEX_TYPE::ScalarType W(VERTEX_TYPE &/*v*/) {return 1.0;}
static void Merge(VERTEX_TYPE & /*v_dest*/, VERTEX_TYPE const & /*v_del*/){} static void Merge(VERTEX_TYPE & /*v_dest*/, VERTEX_TYPE const & /*v_del*/){}
}; };
class TriEdgeCollapseQuadricParameter : public BaseParameterClass class TriEdgeCollapseQuadricParameter : public BaseParameterClass
@ -189,11 +189,11 @@ public:
// typedef typename TEC::EdgeType EdgeType; // typedef typename TEC::EdgeType EdgeType;
typedef typename TriEdgeCollapse<TriMeshType, VertexPair, MYTYPE>::HeapType HeapType; typedef typename TriEdgeCollapse<TriMeshType, VertexPair, MYTYPE>::HeapType HeapType;
typedef typename TriEdgeCollapse<TriMeshType, VertexPair, MYTYPE>::HeapElem HeapElem; typedef typename TriEdgeCollapse<TriMeshType, VertexPair, MYTYPE>::HeapElem HeapElem;
typedef typename TriMeshType::CoordType CoordType; typedef typename TriMeshType::CoordType CoordType;
typedef typename TriMeshType::ScalarType ScalarType; typedef typename TriMeshType::ScalarType ScalarType;
typedef math::Quadric< double > QuadricType; typedef math::Quadric< double > QuadricType;
typedef typename TriMeshType::FaceType FaceType; typedef typename TriMeshType::FaceType FaceType;
typedef typename TriMeshType::VertexType VertexType; typedef typename TriMeshType::VertexType VertexType;
typedef TriEdgeCollapseQuadricParameter QParameter; typedef TriEdgeCollapseQuadricParameter QParameter;
typedef HelperType QH; typedef HelperType QH;
@ -203,19 +203,19 @@ public:
// } // }
// puntatori ai vertici che sono stati messi non-w per preservare il boundary // puntatori ai vertici che sono stati messi non-w per preservare il boundary
static std::vector<typename TriMeshType::VertexPointer> & WV(){ static std::vector<typename TriMeshType::VertexPointer> & WV(){
static std::vector<typename TriMeshType::VertexPointer> _WV; return _WV; static std::vector<typename TriMeshType::VertexPointer> _WV; return _WV;
}; };
inline TriEdgeCollapseQuadric(){} inline TriEdgeCollapseQuadric(){}
inline TriEdgeCollapseQuadric(const VertexPair &p, int i, BaseParameterClass *pp) inline TriEdgeCollapseQuadric(const VertexPair &p, int i, BaseParameterClass *pp)
{ {
this->localMark = i; this->localMark = i;
this->pos=p; this->pos=p;
this->_priority = ComputePriority(pp); this->_priority = ComputePriority(pp);
} }
inline bool IsFeasible(BaseParameterClass *_pp){ inline bool IsFeasible(BaseParameterClass *_pp){
@ -238,8 +238,8 @@ public:
EdgeCollapser<TriMeshType,VertexPair>::Do(m, this->pos, newPos); // v0 is deleted and v1 take the new position EdgeCollapser<TriMeshType,VertexPair>::Do(m, this->pos, newPos); // v0 is deleted and v1 take the new position
} }
// Final Clean up after the end of the simplification process // Final Clean up after the end of the simplification process
static void Finalize(TriMeshType &m, HeapType& /*h_ret*/, BaseParameterClass *_pp) static void Finalize(TriMeshType &m, HeapType& /*h_ret*/, BaseParameterClass *_pp)
{ {
@ -249,7 +249,7 @@ public:
if(pp->FastPreserveBoundary) if(pp->FastPreserveBoundary)
{ {
typename TriMeshType::VertexIterator vi; typename TriMeshType::VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) for(vi=m.vert.begin();vi!=m.vert.end();++vi)
if(!(*vi).IsD()) (*vi).SetW(); if(!(*vi).IsD()) (*vi).SetW();
} }
if(pp->PreserveBoundary) if(pp->PreserveBoundary)
@ -324,31 +324,31 @@ public:
} }
} }
} }
else else
{ // if the collapse is A-symmetric (e.g. u->v != v->u) { // if the collapse is A-symmetric (e.g. u->v != v->u)
for(vi=m.vert.begin();vi!=m.vert.end();++vi) for(vi=m.vert.begin();vi!=m.vert.end();++vi)
if(!(*vi).IsD() && (*vi).IsRW()) if(!(*vi).IsD() && (*vi).IsRW())
{ {
vcg::face::VFIterator<FaceType> x; vcg::face::VFIterator<FaceType> x;
UnMarkAll(m); UnMarkAll(m);
for( x.F() = (*vi).VFp(), x.I() = (*vi).VFi(); x.F()!=0; ++ x) for( x.F() = (*vi).VFp(), x.I() = (*vi).VFi(); x.F()!=0; ++ x)
{ {
assert(x.F()->V(x.I())==&(*vi)); assert(x.F()->V(x.I())==&(*vi));
if(x.V()->IsRW() && x.V1()->IsRW() && !IsMarked(m,x.F()->V1(x.I()))){ if(x.V()->IsRW() && x.V1()->IsRW() && !IsMarked(m,x.F()->V1(x.I()))){
h_ret.push_back( HeapElem( new MYTYPE( VertexPair (x.V(),x.V1()),TriEdgeCollapse< TriMeshType,VertexPair,MYTYPE>::GlobalMark(),_pp))); h_ret.push_back( HeapElem( new MYTYPE( VertexPair (x.V(),x.V1()),TriEdgeCollapse< TriMeshType,VertexPair,MYTYPE>::GlobalMark(),_pp)));
} }
if(x.V()->IsRW() && x.V2()->IsRW() && !IsMarked(m,x.F()->V2(x.I()))){ if(x.V()->IsRW() && x.V2()->IsRW() && !IsMarked(m,x.F()->V2(x.I()))){
h_ret.push_back( HeapElem( new MYTYPE( VertexPair (x.V(),x.V2()),TriEdgeCollapse< TriMeshType,VertexPair,MYTYPE>::GlobalMark(),_pp))); h_ret.push_back( HeapElem( new MYTYPE( VertexPair (x.V(),x.V2()),TriEdgeCollapse< TriMeshType,VertexPair,MYTYPE>::GlobalMark(),_pp)));
} }
} }
} }
} }
} }
static float HeapSimplexRatio(BaseParameterClass *_pp) {return IsSymmetric(_pp)?5.0f:9.0f;} static float HeapSimplexRatio(BaseParameterClass *_pp) {return IsSymmetric(_pp)?5.0f:9.0f;}
static bool IsSymmetric(BaseParameterClass *_pp) {return ((QParameter *)_pp)->OptimalPlacement;} static bool IsSymmetric(BaseParameterClass *_pp) {return ((QParameter *)_pp)->OptimalPlacement;}
static bool IsVertexStable(BaseParameterClass *_pp) {return !((QParameter *)_pp)->OptimalPlacement;} static bool IsVertexStable(BaseParameterClass *_pp) {return !((QParameter *)_pp)->OptimalPlacement;}
///* ///*
// Funzione principale di valutazione dell'errore del collasso. // Funzione principale di valutazione dell'errore del collasso.
// In pratica simula il collasso vero e proprio. // In pratica simula il collasso vero e proprio.
@ -358,96 +358,96 @@ public:
ScalarType ComputePriority(BaseParameterClass *_pp) ScalarType ComputePriority(BaseParameterClass *_pp)
{ {
QParameter *pp=(QParameter *)_pp; QParameter *pp=(QParameter *)_pp;
ScalarType error; ScalarType error;
typename vcg::face::VFIterator<FaceType> x; typename vcg::face::VFIterator<FaceType> x;
std::vector<CoordType> on; // original normals std::vector<CoordType> on; // original normals
typename TriMeshType::VertexType * v[2]; typename TriMeshType::VertexType * v[2];
v[0] = this->pos.V(0); v[0] = this->pos.V(0);
v[1] = this->pos.V(1); v[1] = this->pos.V(1);
if(pp->NormalCheck){ // Compute maximal normal variation if(pp->NormalCheck){ // Compute maximal normal variation
// store the old normals for non-collapsed face in v0 // store the old normals for non-collapsed face in v0
for(x.F() = v[0]->VFp(), x.I() = v[0]->VFi(); x.F()!=0; ++x ) // for all faces in v0 for(x.F() = v[0]->VFp(), x.I() = v[0]->VFi(); x.F()!=0; ++x ) // for all faces in v0
if(x.F()->V(0)!=v[1] && x.F()->V(1)!=v[1] && x.F()->V(2)!=v[1] ) // skip faces with v1 if(x.F()->V(0)!=v[1] && x.F()->V(1)!=v[1] && x.F()->V(2)!=v[1] ) // skip faces with v1
on.push_back(NormalizedNormal(*x.F())); on.push_back(TriangleNormal(*x.F()).Normalize());
// store the old normals for non-collapsed face in v1 // store the old normals for non-collapsed face in v1
for(x.F() = v[1]->VFp(), x.I() = v[1]->VFi(); x.F()!=0; ++x ) // for all faces in v1 for(x.F() = v[1]->VFp(), x.I() = v[1]->VFi(); x.F()!=0; ++x ) // for all faces in v1
if(x.F()->V(0)!=v[0] && x.F()->V(1)!=v[0] && x.F()->V(2)!=v[0] ) // skip faces with v0 if(x.F()->V(0)!=v[0] && x.F()->V(1)!=v[0] && x.F()->V(2)!=v[0] ) // skip faces with v0
on.push_back(NormalizedNormal(*x.F())); on.push_back(TriangleNormal(*x.F()).Normalize());
} }
//// Move the two vertexe into new position (storing the old ones) //// Move the two vertexe into new position (storing the old ones)
CoordType OldPos0=v[0]->P(); CoordType OldPos0=v[0]->P();
CoordType OldPos1=v[1]->P(); CoordType OldPos1=v[1]->P();
if(pp->OptimalPlacement) { v[0]->P() = ComputeMinimal(); v[1]->P()=v[0]->P();} if(pp->OptimalPlacement) { v[0]->P() = ComputeMinimal(); v[1]->P()=v[0]->P();}
else v[0]->P() = v[1]->P(); else v[0]->P() = v[1]->P();
//// Rescan faces and compute quality and difference between normals //// Rescan faces and compute quality and difference between normals
int i; int i;
double ndiff,MinCos = 1e100; // minimo coseno di variazione di una normale della faccia double ndiff,MinCos = 1e100; // minimo coseno di variazione di una normale della faccia
// (e.g. max angle) Mincos varia da 1 (normali coincidenti) a // (e.g. max angle) Mincos varia da 1 (normali coincidenti) a
// -1 (normali opposte); // -1 (normali opposte);
double qt, MinQual = 1e100; double qt, MinQual = 1e100;
CoordType nn; CoordType nn;
for(x.F() = v[0]->VFp(), x.I() = v[0]->VFi(),i=0; x.F()!=0; ++x ) // for all faces in v0 for(x.F() = v[0]->VFp(), x.I() = v[0]->VFi(),i=0; x.F()!=0; ++x ) // for all faces in v0
if(x.F()->V(0)!=v[1] && x.F()->V(1)!=v[1] && x.F()->V(2)!=v[1] ) // skip faces with v1 if(x.F()->V(0)!=v[1] && x.F()->V(1)!=v[1] && x.F()->V(2)!=v[1] ) // skip faces with v1
{ {
if(pp->NormalCheck){ if(pp->NormalCheck){
nn=NormalizedNormal(*x.F()); nn=TriangleNormal(*x.F()).Normalize();
ndiff=nn.dot(on[i++]); ndiff=nn.dot(on[i++]);
if(ndiff<MinCos) MinCos=ndiff; if(ndiff<MinCos) MinCos=ndiff;
} }
if(pp->QualityCheck){ if(pp->QualityCheck){
qt= QualityFace(*x.F()); qt= QualityFace(*x.F());
if(qt<MinQual) MinQual=qt; if(qt<MinQual) MinQual=qt;
} }
} }
for(x.F() = v[1]->VFp(), x.I() = v[1]->VFi(),i=0; x.F()!=0; ++x ) // for all faces in v1 for(x.F() = v[1]->VFp(), x.I() = v[1]->VFi(),i=0; x.F()!=0; ++x ) // for all faces in v1
if(x.F()->V(0)!=v[0] && x.F()->V(1)!=v[0] && x.F()->V(2)!=v[0] ) // skip faces with v0 if(x.F()->V(0)!=v[0] && x.F()->V(1)!=v[0] && x.F()->V(2)!=v[0] ) // skip faces with v0
{ {
if(pp->NormalCheck){ if(pp->NormalCheck){
nn=NormalizedNormal(*x.F()); nn=TriangleNormal(*x.F()).Normalize();
ndiff=nn.dot(on[i++]); ndiff=nn.dot(on[i++]);
if(ndiff<MinCos) MinCos=ndiff; if(ndiff<MinCos) MinCos=ndiff;
} }
if(pp->QualityCheck){ if(pp->QualityCheck){
qt= QualityFace(*x.F()); qt= QualityFace(*x.F());
if(qt<MinQual) MinQual=qt; if(qt<MinQual) MinQual=qt;
} }
} }
QuadricType qq=QH::Qd(v[0]); QuadricType qq=QH::Qd(v[0]);
qq+=QH::Qd(v[1]); qq+=QH::Qd(v[1]);
Point3d tpd=Point3d::Construct(v[1]->P()); Point3d tpd=Point3d::Construct(v[1]->P());
double QuadErr = pp->ScaleFactor*qq.Apply(tpd); double QuadErr = pp->ScaleFactor*qq.Apply(tpd);
// All collapses involving triangles with quality larger than <QualityThr> has no penalty; // All collapses involving triangles with quality larger than <QualityThr> has no penalty;
if(MinQual>pp->QualityThr) MinQual=pp->QualityThr; if(MinQual>pp->QualityThr) MinQual=pp->QualityThr;
if(pp->NormalCheck){ if(pp->NormalCheck){
// All collapses where the normal vary less than <NormalThr> (e.g. more than CosineThr) // All collapses where the normal vary less than <NormalThr> (e.g. more than CosineThr)
// have no penalty // have no penalty
if(MinCos>pp->CosineThr) MinCos=pp->CosineThr; if(MinCos>pp->CosineThr) MinCos=pp->CosineThr;
MinCos=(MinCos+1)/2.0; // Now it is in the range 0..1 with 0 very dangerous! MinCos=(MinCos+1)/2.0; // Now it is in the range 0..1 with 0 very dangerous!
} }
if(QuadErr<pp->QuadricEpsilon) QuadErr=pp->QuadricEpsilon; if(QuadErr<pp->QuadricEpsilon) QuadErr=pp->QuadricEpsilon;
if( pp->UseVertexWeight ) QuadErr *= (QH::W(v[1])+QH::W(v[0]))/2; if( pp->UseVertexWeight ) QuadErr *= (QH::W(v[1])+QH::W(v[0]))/2;
if(!pp->QualityCheck && !pp->NormalCheck) error = (ScalarType)(QuadErr); if(!pp->QualityCheck && !pp->NormalCheck) error = (ScalarType)(QuadErr);
if( pp->QualityCheck && !pp->NormalCheck) error = (ScalarType)(QuadErr / MinQual); if( pp->QualityCheck && !pp->NormalCheck) error = (ScalarType)(QuadErr / MinQual);
if(!pp->QualityCheck && pp->NormalCheck) error = (ScalarType)(QuadErr / MinCos); if(!pp->QualityCheck && pp->NormalCheck) error = (ScalarType)(QuadErr / MinCos);
if( pp->QualityCheck && pp->NormalCheck) error = (ScalarType)(QuadErr / (MinQual*MinCos)); if( pp->QualityCheck && pp->NormalCheck) error = (ScalarType)(QuadErr / (MinQual*MinCos));
//Rrestore old position of v0 and v1
v[0]->P()=OldPos0;
v[1]->P()=OldPos1;
this->_priority = error;
return this->_priority;
}
// //Rrestore old position of v0 and v1
v[0]->P()=OldPos0;
v[1]->P()=OldPos1;
this->_priority = error;
return this->_priority;
}
//
//static double MaxError() {return 1e100;} //static double MaxError() {return 1e100;}
// //
inline void UpdateHeap(HeapType & h_ret,BaseParameterClass *_pp) inline void UpdateHeap(HeapType & h_ret,BaseParameterClass *_pp)
@ -510,72 +510,72 @@ public:
static void InitQuadric(TriMeshType &m,BaseParameterClass *_pp) static void InitQuadric(TriMeshType &m,BaseParameterClass *_pp)
{ {
QParameter *pp=(QParameter *)_pp; QParameter *pp=(QParameter *)_pp;
typename TriMeshType::FaceIterator pf; typename TriMeshType::FaceIterator pf;
typename TriMeshType::VertexIterator pv; typename TriMeshType::VertexIterator pv;
int j; int j;
QH::Init(); QH::Init();
// m.ClearFlags(); // m.ClearFlags();
for(pv=m.vert.begin();pv!=m.vert.end();++pv) // Azzero le quadriche for(pv=m.vert.begin();pv!=m.vert.end();++pv) // Azzero le quadriche
if( ! (*pv).IsD() && (*pv).IsW()) if( ! (*pv).IsD() && (*pv).IsW())
QH::Qd(*pv).SetZero(); QH::Qd(*pv).SetZero();
for(pf=m.face.begin();pf!=m.face.end();++pf) for(pf=m.face.begin();pf!=m.face.end();++pf)
if( !(*pf).IsD() && (*pf).IsR() ) if( !(*pf).IsD() && (*pf).IsR() )
if((*pf).V(0)->IsR() &&(*pf).V(1)->IsR() &&(*pf).V(2)->IsR()) if((*pf).V(0)->IsR() &&(*pf).V(1)->IsR() &&(*pf).V(2)->IsR())
{ {
QuadricType q; QuadricType q;
Plane3<ScalarType,false> p; Plane3<ScalarType,false> p;
// Calcolo piano // Calcolo piano
p.SetDirection( ( (*pf).V(1)->cP() - (*pf).V(0)->cP() ) ^ ( (*pf).V(2)->cP() - (*pf).V(0)->cP() )); p.SetDirection( ( (*pf).V(1)->cP() - (*pf).V(0)->cP() ) ^ ( (*pf).V(2)->cP() - (*pf).V(0)->cP() ));
// Se normalizzo non dipende dall'area // Se normalizzo non dipende dall'area
if(!pp->UseArea) if(!pp->UseArea)
p.Normalize(); p.Normalize();
p.SetOffset( p.Direction().dot((*pf).V(0)->cP())); p.SetOffset( p.Direction().dot((*pf).V(0)->cP()));
// Calcolo quadrica delle facce // Calcolo quadrica delle facce
q.ByPlane(p); q.ByPlane(p);
for(j=0;j<3;++j) for(j=0;j<3;++j)
if( (*pf).V(j)->IsW() ) if( (*pf).V(j)->IsW() )
{ {
if(pp->QualityWeight) if(pp->QualityWeight)
q*=(*pf).V(j)->Q(); q*=(*pf).V(j)->Q();
QH::Qd((*pf).V(j)) += q; // Sommo la quadrica ai vertici QH::Qd((*pf).V(j)) += q; // Sommo la quadrica ai vertici
} }
for(j=0;j<3;++j)
if( (*pf).IsB(j) || pp->QualityQuadric ) // Bordo!
{
Plane3<ScalarType,false> pb; // Piano di bordo
// Calcolo la normale al piano di bordo e la sua distanza for(j=0;j<3;++j)
// Nota che la lunghezza dell'edge DEVE essere Normalizzata if( (*pf).IsB(j) || pp->QualityQuadric ) // Bordo!
// poiche' la pesatura in funzione dell'area e'gia fatta in p.Direction() {
// Senza la normalize il bordo e' pesato in funzione della grandezza della mesh (mesh grandi non decimano sul bordo) Plane3<ScalarType,false> pb; // Piano di bordo
pb.SetDirection(p.Direction() ^ ( (*pf).V1(j)->cP() - (*pf).V(j)->cP() ).normalized());
// Calcolo la normale al piano di bordo e la sua distanza
// Nota che la lunghezza dell'edge DEVE essere Normalizzata
// poiche' la pesatura in funzione dell'area e'gia fatta in p.Direction()
// Senza la normalize il bordo e' pesato in funzione della grandezza della mesh (mesh grandi non decimano sul bordo)
pb.SetDirection(p.Direction() ^ ( (*pf).V1(j)->cP() - (*pf).V(j)->cP() ).normalized());
if( (*pf).IsB(j) ) pb.SetDirection(pb.Direction()* (ScalarType)pp->BoundaryWeight); // amplify border planes if( (*pf).IsB(j) ) pb.SetDirection(pb.Direction()* (ScalarType)pp->BoundaryWeight); // amplify border planes
else pb.SetDirection(pb.Direction()* (ScalarType)(pp->BoundaryWeight/100.0)); // and consider much less quadric for quality else pb.SetDirection(pb.Direction()* (ScalarType)(pp->BoundaryWeight/100.0)); // and consider much less quadric for quality
pb.SetOffset(pb.Direction().dot((*pf).V(j)->cP())); pb.SetOffset(pb.Direction().dot((*pf).V(j)->cP()));
q.ByPlane(pb); q.ByPlane(pb);
if( (*pf).V (j)->IsW() ) QH::Qd((*pf).V (j)) += q; // Sommo le quadriche
if( (*pf).V1(j)->IsW() ) QH::Qd((*pf).V1(j)) += q;
}
}
if( (*pf).V (j)->IsW() ) QH::Qd((*pf).V (j)) += q; // Sommo le quadriche
if( (*pf).V1(j)->IsW() ) QH::Qd((*pf).V1(j)) += q;
}
}
if(pp->ScaleIndependent) if(pp->ScaleIndependent)
{ {
vcg::tri::UpdateBounding<TriMeshType>::Box(m); vcg::tri::UpdateBounding<TriMeshType>::Box(m);
//Make all quadric independent from mesh size //Make all quadric independent from mesh size
pp->ScaleFactor = 1e8*pow(1.0/m.bbox.Diag(),6); // scaling factor pp->ScaleFactor = 1e8*pow(1.0/m.bbox.Diag(),6); // scaling factor
//pp->ScaleFactor *=pp->ScaleFactor ; //pp->ScaleFactor *=pp->ScaleFactor ;
//pp->ScaleFactor *=pp->ScaleFactor ; //pp->ScaleFactor *=pp->ScaleFactor ;
//printf("Scale factor =%f\n",pp->ScaleFactor ); //printf("Scale factor =%f\n",pp->ScaleFactor );
//printf("bb (%5.2f %5.2f %5.2f)-(%5.2f %5.2f %5.2f) Diag %f\n",m.bbox.min[0],m.bbox.min[1],m.bbox.min[2],m.bbox.max[0],m.bbox.max[1],m.bbox.max[2],m.bbox.Diag()); //printf("bb (%5.2f %5.2f %5.2f)-(%5.2f %5.2f %5.2f) Diag %f\n",m.bbox.min[0],m.bbox.min[1],m.bbox.min[2],m.bbox.max[0],m.bbox.max[1],m.bbox.max[2],m.bbox.Diag());
} }
} }
@ -594,33 +594,33 @@ public:
// } // }
// //
CoordType ComputeMinimal() CoordType ComputeMinimal()
{ {
typename TriMeshType::VertexType * v[2]; typename TriMeshType::VertexType * v[2];
v[0] = this->pos.V(0); v[0] = this->pos.V(0);
v[1] = this->pos.V(1); v[1] = this->pos.V(1);
QuadricType q=QH::Qd(v[0]); QuadricType q=QH::Qd(v[0]);
q+=QH::Qd(v[1]); q+=QH::Qd(v[1]);
Point3<QuadricType::ScalarType> x; Point3<QuadricType::ScalarType> x;
bool rt=q.Minimum(x); bool rt=q.Minimum(x);
if(!rt) { // if the computation of the minimum fails we choose between the two edge points and the middle one. if(!rt) { // if the computation of the minimum fails we choose between the two edge points and the middle one.
Point3<QuadricType::ScalarType> x0=Point3d::Construct(v[0]->P()); Point3<QuadricType::ScalarType> x0=Point3d::Construct(v[0]->P());
Point3<QuadricType::ScalarType> x1=Point3d::Construct(v[1]->P()); Point3<QuadricType::ScalarType> x1=Point3d::Construct(v[1]->P());
x.Import((v[0]->P()+v[1]->P())/2); x.Import((v[0]->P()+v[1]->P())/2);
double qvx=q.Apply(x); double qvx=q.Apply(x);
double qv0=q.Apply(x0); double qv0=q.Apply(x0);
double qv1=q.Apply(x1); double qv1=q.Apply(x1);
if(qv0<qvx) x=x0; if(qv0<qvx) x=x0;
if(qv1<qvx && qv1<qv0) x=x1; if(qv1<qvx && qv1<qv0) x=x1;
} }
return CoordType::Construct(x); return CoordType::Construct(x);
} }
// //
// //
}; };
} // namespace tri } // namespace tri
} // namespace vcg } // namespace vcg
#endif #endif

View File

@ -340,7 +340,7 @@ class TriEdgeCollapseQuadricTex: public vcg::tri::TriEdgeCollapse< TriMeshType,
qt= QualityFace(*x.F()); qt= QualityFace(*x.F());
if(qt<MinQual) MinQual=qt; if(qt<MinQual) MinQual=qt;
if(pp->NormalCheck){ if(pp->NormalCheck){
CoordType nn=NormalizedNormal(*x.F()); CoordType nn=TriangleNormal(*x.F()).Normalize();
ndiff=nn.dot(x.F()->N()) / x.F()->N().Norm(); ndiff=nn.dot(x.F()->N()) / x.F()->N().Norm();
if(ndiff<MinCos) MinCos=ndiff; if(ndiff<MinCos) MinCos=ndiff;
assert(!math::IsNAN(ndiff)); assert(!math::IsNAN(ndiff));
@ -352,7 +352,7 @@ class TriEdgeCollapseQuadricTex: public vcg::tri::TriEdgeCollapse< TriMeshType,
qt= QualityFace(*x.F()); qt= QualityFace(*x.F());
if(qt<MinQual) MinQual=qt; if(qt<MinQual) MinQual=qt;
if(pp->NormalCheck){ if(pp->NormalCheck){
CoordType nn=NormalizedNormal(*x.F()); CoordType nn=TriangleNormal(*x.F()).Normalize();
ndiff=nn.dot(x.F()->N() / x.F()->N().Norm()); ndiff=nn.dot(x.F()->N() / x.F()->N().Norm());
if(ndiff<MinCos) MinCos=ndiff; if(ndiff<MinCos) MinCos=ndiff;
assert(!math::IsNAN(ndiff)); assert(!math::IsNAN(ndiff));

View File

@ -247,7 +247,7 @@ So it just require that you have correctly computed the flags; one way could be
\code \code
vcg::tri::UpdateTopology<Mesh>::FaceFace(m.cm); vcg::tri::UpdateTopology<Mesh>::FaceFace(m.cm);
vcg::tri::UpdateFlags<Mesh>::FaceBorderFromFF(m.cm); vcg::tri::UpdateFlags<Mesh>::FaceBorderFromFF(m.cm);
vcg::tri::UpdateFlags<Mesh>::VertexBorderFromFace (m.cm); vcg::tri::UpdateFlags<Mesh>::VertexBorderFromFaceBorder (m.cm);
vcg::tri::UpdateColor<Mesh>::PerVertexBorderFlag(m.cm); vcg::tri::UpdateColor<Mesh>::PerVertexBorderFlag(m.cm);
\endcode \endcode
*/ */

View File

@ -503,7 +503,7 @@ static void ConvertVoronoiDiagramToMesh(MeshType &m,
if(vpp.triangulateRegion) if(vpp.triangulateRegion)
{ {
tri::UpdateFlags<MeshType>::FaceBorderFromFF(outMesh); tri::UpdateFlags<MeshType>::FaceBorderFromFF(outMesh);
tri::UpdateFlags<MeshType>::VertexBorderFromFace(outMesh); tri::UpdateFlags<MeshType>::VertexBorderFromFaceBorder(outMesh);
for(FaceIterator fi=outMesh.face.begin();fi!=outMesh.face.end();++fi) if(!fi->IsD()) for(FaceIterator fi=outMesh.face.begin();fi!=outMesh.face.end();++fi) if(!fi->IsD())
{ {
for(int i=0;i<3;++i) for(int i=0;i<3;++i)
@ -734,7 +734,7 @@ static void ConvertVoronoiDiagramToMeshOld(MeshType &m,
tri::Allocator<MeshType>::CompactEveryVector(outMesh); tri::Allocator<MeshType>::CompactEveryVector(outMesh);
tri::UpdateTopology<MeshType>::FaceFace(outMesh); tri::UpdateTopology<MeshType>::FaceFace(outMesh);
tri::UpdateFlags<MeshType>::FaceBorderFromFF(outMesh); tri::UpdateFlags<MeshType>::FaceBorderFromFF(outMesh);
tri::UpdateFlags<MeshType>::VertexBorderFromFace(outMesh); tri::UpdateFlags<MeshType>::VertexBorderFromFaceBorder(outMesh);
// 3) set up faux bits // 3) set up faux bits
for(FaceIterator fi=outMesh.face.begin();fi!=outMesh.face.end();++fi) for(FaceIterator fi=outMesh.face.begin();fi!=outMesh.face.end();++fi)
@ -1282,7 +1282,7 @@ static int VoronoiRelaxing(MeshType &m, std::vector<VertexType *> &seedVec,
} }
tri::UpdateFlags<MeshType>::FaceBorderFromVF(m); tri::UpdateFlags<MeshType>::FaceBorderFromVF(m);
tri::UpdateFlags<MeshType>::VertexBorderFromFace(m); tri::UpdateFlags<MeshType>::VertexBorderFromFaceBorder(m);
PerVertexPointerHandle sources = tri::Allocator<MeshType>:: template GetPerVertexAttribute<VertexPointer> (m,"sources"); PerVertexPointerHandle sources = tri::Allocator<MeshType>:: template GetPerVertexAttribute<VertexPointer> (m,"sources");
PerVertexBoolHandle fixed = tri::Allocator<MeshType>:: template GetPerVertexAttribute<bool> (m,"fixed"); PerVertexBoolHandle fixed = tri::Allocator<MeshType>:: template GetPerVertexAttribute<bool> (m,"fixed");
int iter; int iter;