2004-09-15 12:25:20 +02:00
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright ( C ) 2004 \ / ) \ / *
* Visual Computing Lab / \ / | *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved . *
* *
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation ; either version 2 of the License , or *
* ( at your option ) any later version . *
* *
* This program is distributed in the hope that it will be useful , *
* but WITHOUT ANY WARRANTY ; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the *
* GNU General Public License ( http : //www.gnu.org/licenses/gpl.txt) *
* for more details . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/****************************************************************************
History
$ Log : not supported by cvs2svn $
2007-10-16 18:46:53 +02:00
Revision 1.14 2007 / 03 / 22 11 : 07 : 16 cignoni
Solved an issue related to different casting double - float between gcc 3 and gcc 4
2007-03-22 12:07:16 +01:00
Revision 1.13 2007 / 02 / 25 09 : 20 : 10 cignoni
Added Rad to the NormalThr Option and removed a bug in multiple exectuion of non optimal simplification ( missing an isD check )
2007-02-25 10:20:10 +01:00
Revision 1.12 2007 / 01 / 19 09 : 13 : 14 cignoni
Added Finalize ( ) method to the interface , corrected minor bugs on border preserving and postsimplification cleanup
Avoided double make_heap ( it is done only in the local_optimization init )
2007-01-19 10:13:14 +01:00
Revision 1.11 2006 / 10 / 15 07 : 31 : 21 cignoni
typenames and qualifiers for gcc compliance
2006-10-15 09:31:22 +02:00
Revision 1.10 2006 / 10 / 09 20 : 12 : 55 cignoni
Heavyly restructured for meshlab inclusion . Now the access to the quadric elements are mediated by a static helper class .
2006-10-09 22:12:55 +02:00
Revision 1.9 2006 / 10 / 07 17 : 20 : 25 cignoni
Updated to the new style face - > Normal ( ) becomes Normal ( face )
2006-10-07 19:20:25 +02:00
Revision 1.8 2005 / 10 / 02 23 : 19 : 36 cignoni
Changed the sign of the priority of a collapse . Now it is its the error as it should ( and not - error )
2005-10-03 01:19:36 +02:00
Revision 1.7 2005 / 04 / 14 11 : 35 : 07 ponchio
* * * empty log message * * *
2005-04-14 13:35:09 +02:00
Revision 1.6 2005 / 01 / 19 10 : 35 : 28 cignoni
Better management of symmetric / asymmetric edge collapses
2005-01-19 11:35:28 +01:00
Revision 1.5 2004 / 12 / 10 01 : 07 : 15 cignoni
Moved param classes inside ; added support for optimal placement and symmetric ; added update heap also here ( not only in the base class )
2004-12-10 02:07:15 +01:00
Revision 1.4 2004 / 11 / 23 10 : 34 : 23 cignoni
passed parameters by reference in many funcs and gcc cleaning
2004-11-23 11:34:45 +01:00
Revision 1.3 2004 / 10 / 25 07 : 07 : 56 ganovelli
A vcg . : : Pos was used to implement the collapse type . CHanged
to vcg : : Edge
2004-10-25 09:07:56 +02:00
Revision 1.2 2004 / 09 / 29 17 : 08 : 16 ganovelli
corrected error in - error ( see localoptimization )
2004-09-15 12:25:20 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifndef __VCG_TRIMESHCOLLAPSE_QUADRIC__
# define __VCG_TRIMESHCOLLAPSE_QUADRIC__
# include <vcg/math/quadric.h>
# include <vcg/simplex/face/pos.h>
# include <vcg/complex/trimesh/update/flag.h>
# include <vcg/complex/trimesh/update/bounding.h>
# include <vcg/complex/local_optimization/tri_edge_collapse.h>
# include <vcg/complex/local_optimization.h>
namespace vcg {
namespace tri {
2004-12-10 02:07:15 +01:00
2004-09-15 12:25:20 +02:00
/**
This class describe Quadric based collapse operation .
Requirements :
Vertex
must have :
2006-10-09 22:12:55 +02:00
incremental mark
VF topology
must have :
members
QuadricType Qd ( ) ;
2004-09-15 12:25:20 +02:00
ScalarType W ( ) const ;
A per - vertex Weight that can be used in simplification
lower weight means that error is lowered ,
standard : return W = = 1.0
void Merge ( MESH_TYPE : : vertex_type const & v ) ;
Merges the attributes of the current vertex with the ones of v
( e . g . its weight with the one of the given vertex , the color ect ) .
Standard : void function ;
2006-10-09 22:12:55 +02:00
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 .
2004-09-15 12:25:20 +02:00
*/
2006-10-09 22:12:55 +02:00
//**Helper CLASSES**//
template < class VERTEX_TYPE >
class QInfoStandard
{
public :
QInfoStandard ( ) { } ;
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 ( ) ; }
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 ) { } ;
} ;
2004-09-15 12:25:20 +02:00
2006-10-09 22:12:55 +02:00
class TriEdgeCollapseQuadricParameter
2004-12-10 02:07:15 +01:00
{
public :
double QualityThr ; // all
double BoundaryWeight ;
2007-02-25 10:20:10 +01:00
double NormalThrRad ;
2004-12-10 02:07:15 +01:00
double CosineThr ;
double QuadricEpsilon ;
double ScaleFactor ;
bool UseArea ;
bool UseVertexWeight ;
bool NormalCheck ;
bool QualityCheck ;
bool OptimalPlacement ;
bool MemoryLess ;
bool ComplexCheck ;
bool ScaleIndependent ;
//***********************
2008-07-15 09:15:18 +02:00
bool QualityQuadric ; // During the initialization manage all the edges as border edges adding a set of additional quadrics that are useful mostly for keeping face aspect ratio good.
2004-12-10 02:07:15 +01:00
bool PreserveTopology ;
bool PreserveBoundary ;
bool MarkComplex ;
bool FastPreserveBoundary ;
bool SafeHeapUpdate ;
} ;
2006-10-15 09:31:22 +02:00
template < class TriMeshType , class MYTYPE , class HelperType = QInfoStandard < typename TriMeshType : : VertexType > >
2006-10-09 22:12:55 +02:00
class TriEdgeCollapseQuadric : public TriEdgeCollapse < TriMeshType , MYTYPE >
{
public :
typedef typename vcg : : tri : : TriEdgeCollapse < TriMeshType , MYTYPE > TEC ;
typedef typename TEC : : EdgeType EdgeType ;
typedef typename TriEdgeCollapse < TriMeshType , MYTYPE > : : HeapType HeapType ;
typedef typename TriEdgeCollapse < TriMeshType , MYTYPE > : : HeapElem HeapElem ;
typedef typename TriMeshType : : CoordType CoordType ;
typedef typename TriMeshType : : ScalarType ScalarType ;
typedef math : : Quadric < double > QuadricType ;
typedef typename TriMeshType : : FaceType FaceType ;
typedef typename TriMeshType : : VertexType VertexType ;
typedef TriEdgeCollapseQuadricParameter QParameter ;
typedef HelperType QH ;
2007-03-22 12:07:16 +01:00
static QParameter & Params ( ) {
static QParameter p ;
return p ;
}
2004-09-15 12:25:20 +02:00
enum Hint {
HNHasFFTopology = 0x0001 , // La mesh arriva con la topologia ff gia'fatta
HNHasVFTopology = 0x0002 , // La mesh arriva con la topologia bf gia'fatta
HNHasBorderFlag = 0x0004 // La mesh arriva con i flag di bordo gia' settati
} ;
static int & Hnt ( ) { static int hnt ; return hnt ; } // the current hints
static void SetHint ( Hint hn ) { Hnt ( ) | = hn ; }
static void ClearHint ( Hint hn ) { Hnt ( ) & = ( ~ hn ) ; }
static bool IsSetHint ( Hint hn ) { return ( Hnt ( ) & hn ) ! = 0 ; }
// puntatori ai vertici che sono stati messi non-w per preservare il boundary
2007-01-19 10:13:14 +01:00
static std : : vector < typename TriMeshType : : VertexPointer > & WV ( ) {
static std : : vector < typename TriMeshType : : VertexPointer > _WV ; return _WV ;
} ;
2004-09-15 12:25:20 +02:00
2004-11-23 11:34:45 +01:00
inline TriEdgeCollapseQuadric ( const EdgeType & p , int i )
2004-09-29 19:08:16 +02:00
//:TEC(p,i){}
{
2005-04-14 13:35:09 +02:00
this - > localMark = i ;
this - > pos = p ;
this - > _priority = ComputePriority ( ) ;
2004-09-29 19:08:16 +02:00
}
2004-09-15 12:25:20 +02:00
2004-10-25 09:07:56 +02:00
inline bool IsFeasible ( ) {
2005-04-14 13:35:09 +02:00
bool res = ( ! Params ( ) . PreserveTopology | | LinkConditions ( this - > pos ) ) ;
2004-11-23 11:34:45 +01:00
if ( ! res ) + + ( TriEdgeCollapse < TriMeshType , MYTYPE > : : FailStat : : LinkConditionEdge ( ) ) ;
return res ;
}
2004-09-15 12:25:20 +02:00
void Execute ( TriMeshType & m )
2004-12-10 02:07:15 +01:00
{ CoordType newPos ;
2008-07-03 12:21:17 +02:00
if ( Params ( ) . OptimalPlacement ) newPos = static_cast < MYTYPE * > ( this ) - > ComputeMinimal ( ) ;
2005-04-14 13:35:09 +02:00
else newPos = this - > pos . V ( 1 ) - > P ( ) ;
2006-10-09 22:12:55 +02:00
//this->pos.V(1)->Qd()+=this->pos.V(0)->Qd();
QH : : Qd ( this - > pos . V ( 1 ) ) + = QH : : Qd ( this - > pos . V ( 0 ) ) ;
2007-10-16 18:46:53 +02:00
//int FaceDel=
DoCollapse ( m , this - > pos , newPos ) ; // v0 is deleted and v1 take the new position
//m.fn-=FaceDel;
//--m.vn;
2004-09-15 12:25:20 +02:00
}
2007-01-19 10:13:14 +01:00
// Final Clean up after the end of the simplification process
static void Finalize ( TriMeshType & m , HeapType & h_ret )
{
// if the mesh was prepared with precomputed borderflags
// correctly set them again.
if ( IsSetHint ( HNHasBorderFlag ) )
vcg : : tri : : UpdateFlags < TriMeshType > : : FaceBorderFromVF ( m ) ;
// If we had the boundary preservation we should clean up the writable flags
if ( Params ( ) . FastPreserveBoundary )
{
typename TriMeshType : : VertexIterator vi ;
for ( vi = m . vert . begin ( ) ; vi ! = m . vert . end ( ) ; + + vi )
if ( ! ( * vi ) . IsD ( ) ) ( * vi ) . SetW ( ) ;
}
if ( Params ( ) . FastPreserveBoundary )
{
typename std : : vector < typename TriMeshType : : VertexPointer > : : iterator wvi ;
for ( wvi = WV ( ) . begin ( ) ; wvi ! = WV ( ) . end ( ) ; + + wvi )
if ( ! ( * wvi ) - > IsD ( ) ) ( * wvi ) - > SetW ( ) ;
}
}
2004-09-15 12:25:20 +02:00
static void Init ( TriMeshType & m , HeapType & h_ret ) {
typename TriMeshType : : VertexIterator vi ;
typename TriMeshType : : FaceIterator pf ;
2004-10-25 09:07:56 +02:00
EdgeType av0 , av1 , av01 ;
2007-02-25 10:20:10 +01:00
Params ( ) . CosineThr = cos ( Params ( ) . NormalThrRad ) ;
2004-09-15 12:25:20 +02:00
if ( ! IsSetHint ( HNHasVFTopology ) ) vcg : : tri : : UpdateTopology < TriMeshType > : : VertexFace ( m ) ;
if ( Params ( ) . MarkComplex ) {
vcg : : tri : : UpdateTopology < TriMeshType > : : FaceFace ( m ) ;
vcg : : tri : : UpdateFlags < TriMeshType > : : FaceBorderFromFF ( m ) ;
vcg : : tri : : UpdateTopology < TriMeshType > : : VertexFace ( m ) ;
} // e' un po' piu' lenta ma marca i vertici complex
else
if ( ! IsSetHint ( HNHasBorderFlag ) )
vcg : : tri : : UpdateFlags < TriMeshType > : : FaceBorderFromVF ( m ) ;
if ( Params ( ) . FastPreserveBoundary )
{
for ( pf = m . face . begin ( ) ; pf ! = m . face . end ( ) ; + + pf )
if ( ! ( * pf ) . IsD ( ) & & ( * pf ) . IsW ( ) )
for ( int j = 0 ; j < 3 ; + + j )
if ( ( * pf ) . IsB ( j ) )
{
( * pf ) . V ( j ) - > ClearW ( ) ;
( * pf ) . V1 ( j ) - > ClearW ( ) ;
}
}
if ( Params ( ) . PreserveBoundary )
{
2007-01-19 10:13:14 +01:00
WV ( ) . clear ( ) ;
2004-09-15 12:25:20 +02:00
for ( pf = m . face . begin ( ) ; pf ! = m . face . end ( ) ; + + pf )
if ( ! ( * pf ) . IsD ( ) & & ( * pf ) . IsW ( ) )
for ( int j = 0 ; j < 3 ; + + j )
if ( ( * pf ) . IsB ( j ) )
{
if ( ( * pf ) . V ( j ) - > IsW ( ) ) { ( * pf ) . V ( j ) - > ClearW ( ) ; WV ( ) . push_back ( ( * pf ) . V ( j ) ) ; }
if ( ( * pf ) . V1 ( j ) - > IsW ( ) ) { ( * pf ) . V1 ( j ) - > ClearW ( ) ; WV ( ) . push_back ( ( * pf ) . V1 ( j ) ) ; }
}
}
InitQuadric ( m ) ;
// Initialize the heap with all the possible collapses
2005-01-19 11:35:28 +01:00
if ( IsSymmetric ( ) )
{ // if the collapse is symmetric (e.g. u->v == v->u)
for ( vi = m . vert . begin ( ) ; vi ! = m . vert . end ( ) ; + + vi )
2007-01-19 10:13:14 +01:00
if ( ! ( * vi ) . IsD ( ) & & ( * vi ) . IsRW ( ) )
2004-09-15 12:25:20 +02:00
{
vcg : : face : : VFIterator < FaceType > x ;
for ( x . F ( ) = ( * vi ) . VFp ( ) , x . I ( ) = ( * vi ) . VFi ( ) ; x . F ( ) ! = 0 ; + + x ) {
2005-01-19 11:35:28 +01:00
x . V1 ( ) - > ClearV ( ) ;
x . V2 ( ) - > ClearV ( ) ;
}
for ( x . F ( ) = ( * vi ) . VFp ( ) , x . I ( ) = ( * vi ) . VFi ( ) ; x . F ( ) ! = 0 ; + + x )
{
2004-09-15 12:25:20 +02:00
assert ( x . F ( ) - > V ( x . I ( ) ) = = & ( * vi ) ) ;
2005-01-19 11:35:28 +01:00
if ( ( x . V0 ( ) < x . V1 ( ) ) & & x . V1 ( ) - > IsRW ( ) & & ! x . V1 ( ) - > IsV ( ) ) {
x . V1 ( ) - > SetV ( ) ;
2005-04-14 13:35:09 +02:00
h_ret . push_back ( HeapElem ( new MYTYPE ( EdgeType ( x . V0 ( ) , x . V1 ( ) ) , TriEdgeCollapse < TriMeshType , MYTYPE > : : GlobalMark ( ) ) ) ) ;
2004-09-15 12:25:20 +02:00
}
2005-01-19 11:35:28 +01:00
if ( ( x . V0 ( ) < x . V2 ( ) ) & & x . V2 ( ) - > IsRW ( ) & & ! x . V2 ( ) - > IsV ( ) ) {
x . V2 ( ) - > SetV ( ) ;
2005-04-14 13:35:09 +02:00
h_ret . push_back ( HeapElem ( new MYTYPE ( EdgeType ( x . V0 ( ) , x . V2 ( ) ) , TriEdgeCollapse < TriMeshType , MYTYPE > : : GlobalMark ( ) ) ) ) ;
2004-09-15 12:25:20 +02:00
}
}
2005-01-19 11:35:28 +01:00
}
}
else
{ // if the collapse is A-symmetric (e.g. u->v != v->u)
2004-09-15 12:25:20 +02:00
for ( vi = m . vert . begin ( ) ; vi ! = m . vert . end ( ) ; + + vi )
2007-02-25 10:20:10 +01:00
if ( ! ( * vi ) . IsD ( ) & & ( * vi ) . IsRW ( ) )
{
vcg : : face : : VFIterator < FaceType > x ;
m . UnMarkAll ( ) ;
for ( x . F ( ) = ( * vi ) . VFp ( ) , x . I ( ) = ( * vi ) . VFi ( ) ; x . F ( ) ! = 0 ; + + x )
{
assert ( x . F ( ) - > V ( x . I ( ) ) = = & ( * vi ) ) ;
if ( x . V ( ) - > IsRW ( ) & & x . V1 ( ) - > IsRW ( ) & & ! m . IsMarked ( x . F ( ) - > V1 ( x . I ( ) ) ) ) {
h_ret . push_back ( HeapElem ( new MYTYPE ( EdgeType ( x . V ( ) , x . V1 ( ) ) , TriEdgeCollapse < TriMeshType , MYTYPE > : : GlobalMark ( ) ) ) ) ;
}
if ( x . V ( ) - > IsRW ( ) & & x . V2 ( ) - > IsRW ( ) & & ! m . IsMarked ( x . F ( ) - > V2 ( x . I ( ) ) ) ) {
h_ret . push_back ( HeapElem ( new MYTYPE ( EdgeType ( x . V ( ) , x . V2 ( ) ) , TriEdgeCollapse < TriMeshType , MYTYPE > : : GlobalMark ( ) ) ) ) ;
}
}
}
2005-01-19 11:35:28 +01:00
}
2004-09-15 12:25:20 +02:00
}
2008-07-10 11:44:09 +02:00
static float HeapSimplexRatio ( ) { return IsSymmetric ( ) ? 5.0f : 9.0f ; }
2004-09-15 12:25:20 +02:00
static bool IsSymmetric ( ) { return Params ( ) . OptimalPlacement ; }
static bool IsVertexStable ( ) { return ! Params ( ) . OptimalPlacement ; }
static void SetDefaultParams ( ) {
Params ( ) . UseArea = true ;
Params ( ) . UseVertexWeight = false ;
2004-10-25 09:07:56 +02:00
Params ( ) . NormalCheck = false ;
2007-02-25 10:20:10 +01:00
Params ( ) . NormalThrRad = M_PI / 2 ;
2004-09-15 12:25:20 +02:00
Params ( ) . QualityCheck = true ;
Params ( ) . QualityThr = .1 ;
Params ( ) . BoundaryWeight = .5 ;
2008-07-15 09:15:18 +02:00
Params ( ) . QualityQuadric = false ;
2004-09-15 12:25:20 +02:00
Params ( ) . OptimalPlacement = true ;
Params ( ) . ScaleIndependent = true ;
Params ( ) . ComplexCheck = false ;
2004-09-29 19:08:16 +02:00
Params ( ) . QuadricEpsilon = 1e-15 ;
2004-09-15 12:25:20 +02:00
Params ( ) . ScaleFactor = 1.0 ;
2004-10-25 09:07:56 +02:00
Params ( ) . PreserveTopology = false ;
2004-09-15 12:25:20 +02:00
}
///*
// Funzione principale di valutazione dell'errore del collasso.
// In pratica simula il collasso vero e proprio.
//
// Da ottimizzare il ciclo sulle normali (deve sparire on e si deve usare per face normals)
//*/
2004-09-29 19:08:16 +02:00
ScalarType ComputePriority ( ) {
2004-09-15 12:25:20 +02:00
ScalarType error ;
typename vcg : : face : : VFIterator < FaceType > x ;
std : : vector < CoordType > on ; // original normals
typename TriMeshType : : VertexType * v [ 2 ] ;
2005-04-14 13:35:09 +02:00
v [ 0 ] = this - > pos . V ( 0 ) ;
v [ 1 ] = this - > pos . V ( 1 ) ;
2004-09-15 12:25:20 +02:00
if ( Params ( ) . NormalCheck ) { // Compute maximal normal variation
// store the old normals for non-collapsed face in v0
for ( x . F ( ) = v [ 0 ] - > VFp ( ) , x . I ( ) = v [ 0 ] - > VFi ( ) ; x . F ( ) ! = 0 ; + + x ) // for all faces in v0
if ( x . F ( ) - > V ( 0 ) ! = v [ 1 ] & & x . F ( ) - > V ( 1 ) ! = v [ 1 ] & & x . F ( ) - > V ( 2 ) ! = v [ 1 ] ) // skip faces with v1
2006-10-07 19:20:25 +02:00
on . push_back ( NormalizedNormal ( * x . F ( ) ) ) ;
2004-09-15 12:25:20 +02:00
// store the old normals for non-collapsed face in v1
for ( x . F ( ) = v [ 1 ] - > VFp ( ) , x . I ( ) = v [ 1 ] - > VFi ( ) ; x . F ( ) ! = 0 ; + + x ) // for all faces in v1
if ( x . F ( ) - > V ( 0 ) ! = v [ 0 ] & & x . F ( ) - > V ( 1 ) ! = v [ 0 ] & & x . F ( ) - > V ( 2 ) ! = v [ 0 ] ) // skip faces with v0
2006-10-07 19:20:25 +02:00
on . push_back ( NormalizedNormal ( * x . F ( ) ) ) ;
2004-09-15 12:25:20 +02:00
}
//// Move the two vertexe into new position (storing the old ones)
CoordType OldPos0 = v [ 0 ] - > P ( ) ;
CoordType OldPos1 = v [ 1 ] - > P ( ) ;
2004-12-10 02:07:15 +01:00
if ( Params ( ) . OptimalPlacement ) { v [ 0 ] - > P ( ) = ComputeMinimal ( ) ; v [ 1 ] - > P ( ) = v [ 0 ] - > P ( ) ; }
else v [ 0 ] - > P ( ) = v [ 1 ] - > P ( ) ;
2004-09-15 12:25:20 +02:00
//// Rescan faces and compute quality and difference between normals
int i ;
double ndiff , MinCos = 1e100 ; // minimo coseno di variazione di una normale della faccia
// (e.g. max angle) Mincos varia da 1 (normali coincidenti) a
// -1 (normali opposte);
double qt , MinQual = 1e100 ;
CoordType nn ;
for ( x . F ( ) = v [ 0 ] - > VFp ( ) , x . I ( ) = v [ 0 ] - > VFi ( ) , i = 0 ; x . F ( ) ! = 0 ; + + x ) // for all faces in v0
if ( x . F ( ) - > V ( 0 ) ! = v [ 1 ] & & x . F ( ) - > V ( 1 ) ! = v [ 1 ] & & x . F ( ) - > V ( 2 ) ! = v [ 1 ] ) // skip faces with v1
{
if ( Params ( ) . NormalCheck ) {
2006-10-07 19:20:25 +02:00
nn = NormalizedNormal ( * x . F ( ) ) ;
2004-09-15 12:25:20 +02:00
ndiff = nn * on [ i + + ] ;
if ( ndiff < MinCos ) MinCos = ndiff ;
}
if ( Params ( ) . QualityCheck ) {
2006-10-07 19:20:25 +02:00
qt = QualityFace ( * x . F ( ) ) ;
2004-09-15 12:25:20 +02:00
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
if ( x . F ( ) - > V ( 0 ) ! = v [ 0 ] & & x . F ( ) - > V ( 1 ) ! = v [ 0 ] & & x . F ( ) - > V ( 2 ) ! = v [ 0 ] ) // skip faces with v0
{
if ( Params ( ) . NormalCheck ) {
2006-10-07 19:20:25 +02:00
nn = NormalizedNormal ( * x . F ( ) ) ;
2004-09-15 12:25:20 +02:00
ndiff = nn * on [ i + + ] ;
if ( ndiff < MinCos ) MinCos = ndiff ;
}
if ( Params ( ) . QualityCheck ) {
2006-10-07 19:20:25 +02:00
qt = QualityFace ( * x . F ( ) ) ;
2004-09-15 12:25:20 +02:00
if ( qt < MinQual ) MinQual = qt ;
}
}
2006-10-09 22:12:55 +02:00
QuadricType qq = QH : : Qd ( v [ 0 ] ) ;
qq + = QH : : Qd ( v [ 1 ] ) ;
2007-03-22 12:07:16 +01:00
Point3d tpd = Point3d : : Construct ( v [ 1 ] - > P ( ) ) ;
double QuadErr = Params ( ) . ScaleFactor * qq . Apply ( tpd ) ;
2004-09-15 12:25:20 +02:00
// All collapses involving triangles with quality larger than <QualityThr> has no penalty;
if ( MinQual > Params ( ) . QualityThr ) MinQual = Params ( ) . QualityThr ;
if ( Params ( ) . NormalCheck ) {
// All collapses where the normal vary less than <NormalThr> (e.g. more than CosineThr)
// have no penalty
if ( MinCos > Params ( ) . CosineThr ) MinCos = Params ( ) . CosineThr ;
MinCos = ( MinCos + 1 ) / 2.0 ; // Now it is in the range 0..1 with 0 very dangerous!
}
if ( QuadErr < Params ( ) . QuadricEpsilon ) QuadErr = Params ( ) . QuadricEpsilon ;
2006-10-09 22:12:55 +02:00
if ( Params ( ) . UseVertexWeight ) QuadErr * = ( QH : : W ( v [ 1 ] ) + QH : : W ( v [ 0 ] ) ) / 2 ;
2004-09-15 12:25:20 +02:00
2006-10-07 19:20:25 +02:00
if ( ! Params ( ) . QualityCheck & & ! Params ( ) . NormalCheck ) error = ( ScalarType ) ( QuadErr ) ;
if ( Params ( ) . QualityCheck & & ! Params ( ) . NormalCheck ) error = ( ScalarType ) ( QuadErr / MinQual ) ;
if ( ! Params ( ) . QualityCheck & & Params ( ) . NormalCheck ) error = ( ScalarType ) ( QuadErr / MinCos ) ;
if ( Params ( ) . QualityCheck & & Params ( ) . NormalCheck ) error = ( ScalarType ) ( QuadErr / ( MinQual * MinCos ) ) ;
2004-09-15 12:25:20 +02:00
//Rrestore old position of v0 and v1
v [ 0 ] - > P ( ) = OldPos0 ;
v [ 1 ] - > P ( ) = OldPos1 ;
2005-10-03 01:19:36 +02:00
this - > _priority = error ;
2005-04-14 13:35:09 +02:00
return this - > _priority ;
2004-09-15 12:25:20 +02:00
}
//
//static double MaxError() {return 1e100;}
//
2004-12-10 02:07:15 +01:00
inline void UpdateHeap ( HeapType & h_ret )
{
2005-04-14 13:35:09 +02:00
this - > GlobalMark ( ) + + ;
2004-12-10 02:07:15 +01:00
VertexType * v [ 2 ] ;
2005-04-14 13:35:09 +02:00
v [ 0 ] = this - > pos . V ( 0 ) ;
v [ 1 ] = this - > pos . V ( 1 ) ;
v [ 1 ] - > IMark ( ) = this - > GlobalMark ( ) ;
2004-12-10 02:07:15 +01:00
// First loop around the remaining vertex to unmark visited flags
2005-01-19 11:35:28 +01:00
vcg : : face : : VFIterator < FaceType > vfi ( v [ 1 ] ) ;
2004-12-10 02:07:15 +01:00
while ( ! vfi . End ( ) ) {
2005-01-19 11:35:28 +01:00
vfi . V1 ( ) - > ClearV ( ) ;
vfi . V2 ( ) - > ClearV ( ) ;
2004-12-10 02:07:15 +01:00
+ + vfi ;
}
// Second Loop
2005-01-19 11:35:28 +01:00
vfi = face : : VFIterator < FaceType > ( v [ 1 ] ) ;
while ( ! vfi . End ( ) )
2004-12-10 02:07:15 +01:00
{
assert ( ! vfi . F ( ) - > IsD ( ) ) ;
for ( int j = 0 ; j < 3 ; j + + )
{
2005-01-19 11:35:28 +01:00
if ( ! ( vfi . V1 ( ) - > IsV ( ) ) & & vfi . V1 ( ) - > IsRW ( ) )
2004-12-10 02:07:15 +01:00
{
2005-01-19 11:35:28 +01:00
vfi . V1 ( ) - > SetV ( ) ;
2006-10-07 19:20:25 +02:00
h_ret . push_back ( HeapElem ( new MYTYPE ( EdgeType ( vfi . V0 ( ) , vfi . V1 ( ) ) , this - > GlobalMark ( ) ) ) ) ;
2005-01-19 11:35:28 +01:00
std : : push_heap ( h_ret . begin ( ) , h_ret . end ( ) ) ;
if ( ! IsSymmetric ( ) ) {
2006-10-07 19:20:25 +02:00
h_ret . push_back ( HeapElem ( new MYTYPE ( EdgeType ( vfi . V1 ( ) , vfi . V0 ( ) ) , this - > GlobalMark ( ) ) ) ) ;
2005-01-19 11:35:28 +01:00
std : : push_heap ( h_ret . begin ( ) , h_ret . end ( ) ) ;
}
}
if ( ! ( vfi . V2 ( ) - > IsV ( ) ) & & vfi . V2 ( ) - > IsRW ( ) )
2004-12-10 02:07:15 +01:00
{
2005-01-19 11:35:28 +01:00
vfi . V2 ( ) - > SetV ( ) ;
2006-10-07 19:20:25 +02:00
h_ret . push_back ( HeapElem ( new MYTYPE ( EdgeType ( vfi . V0 ( ) , vfi . V2 ( ) ) , this - > GlobalMark ( ) ) ) ) ;
2005-01-19 11:35:28 +01:00
std : : push_heap ( h_ret . begin ( ) , h_ret . end ( ) ) ;
if ( ! IsSymmetric ( ) ) {
2006-10-07 19:20:25 +02:00
h_ret . push_back ( HeapElem ( new MYTYPE ( EdgeType ( vfi . V2 ( ) , vfi . V0 ( ) ) , this - > GlobalMark ( ) ) ) ) ;
2005-01-19 11:35:28 +01:00
std : : push_heap ( h_ret . begin ( ) , h_ret . end ( ) ) ;
}
}
if ( Params ( ) . SafeHeapUpdate & & vfi . V1 ( ) - > IsRW ( ) & & vfi . V2 ( ) - > IsRW ( ) )
{
2006-10-07 19:20:25 +02:00
h_ret . push_back ( HeapElem ( new MYTYPE ( EdgeType ( vfi . V1 ( ) , vfi . V2 ( ) ) , this - > GlobalMark ( ) ) ) ) ;
2005-01-19 11:35:28 +01:00
std : : push_heap ( h_ret . begin ( ) , h_ret . end ( ) ) ;
if ( ! IsSymmetric ( ) ) {
2006-10-07 19:20:25 +02:00
h_ret . push_back ( HeapElem ( new MYTYPE ( EdgeType ( vfi . V2 ( ) , vfi . V1 ( ) ) , this - > GlobalMark ( ) ) ) ) ;
2005-01-19 11:35:28 +01:00
std : : push_heap ( h_ret . begin ( ) , h_ret . end ( ) ) ;
}
}
2004-12-10 02:07:15 +01:00
}
2005-01-19 11:35:28 +01:00
+ + vfi ;
2004-12-10 02:07:15 +01:00
}
2005-01-19 11:35:28 +01:00
2004-12-10 02:07:15 +01:00
}
2004-09-15 12:25:20 +02:00
static void InitQuadric ( TriMeshType & m )
{
typename TriMeshType : : FaceIterator pf ;
typename TriMeshType : : VertexIterator pv ;
int j ;
2006-10-09 22:12:55 +02:00
QH : : Init ( ) ;
2004-09-15 12:25:20 +02:00
// m.ClearFlags();
for ( pv = m . vert . begin ( ) ; pv ! = m . vert . end ( ) ; + + pv ) // Azzero le quadriche
if ( ! ( * pv ) . IsD ( ) & & ( * pv ) . IsW ( ) )
2006-10-09 22:12:55 +02:00
QH : : Qd ( * pv ) . Zero ( ) ;
2004-09-15 12:25:20 +02:00
for ( pf = m . face . begin ( ) ; pf ! = m . face . end ( ) ; + + pf )
if ( ! ( * pf ) . IsD ( ) & & ( * pf ) . IsR ( ) )
if ( ( * pf ) . V ( 0 ) - > IsR ( ) & & ( * pf ) . V ( 1 ) - > IsR ( ) & & ( * pf ) . V ( 2 ) - > IsR ( ) )
{
QuadricType q ;
Plane3 < ScalarType , false > p ;
// Calcolo piano
p . SetDirection ( ( ( * pf ) . V ( 1 ) - > cP ( ) - ( * pf ) . V ( 0 ) - > cP ( ) ) ^ ( ( * pf ) . V ( 2 ) - > cP ( ) - ( * pf ) . V ( 0 ) - > cP ( ) ) ) ;
// Se normalizzo non dipende dall'area
if ( ! Params ( ) . UseArea )
2004-09-29 19:08:16 +02:00
p . Normalize ( ) ;
2004-09-15 12:25:20 +02:00
p . SetOffset ( p . Direction ( ) * ( * pf ) . V ( 0 ) - > cP ( ) ) ;
// Calcolo quadrica delle facce
q . ByPlane ( p ) ;
for ( j = 0 ; j < 3 ; + + j )
2006-10-09 22:12:55 +02:00
if ( ( * pf ) . V ( j ) - > IsW ( ) ) QH : : Qd ( ( * pf ) . V ( j ) ) + = q ; // Sommo la quadrica ai vertici
2004-09-15 12:25:20 +02:00
for ( j = 0 ; j < 3 ; + + j )
2008-07-15 09:15:18 +02:00
if ( ( * pf ) . IsB ( j ) | | Params ( ) . QualityQuadric ) // Bordo!
2004-09-15 12:25:20 +02:00
{
Plane3 < ScalarType , false > pb ; // Piano di bordo
// Calcolo la normale al piano di bordo e la sua distanza
// Nota che la lunghezza dell'edge DEVE essere Normalizzata
// poiche' la pesatura in funzione dell'area e'gia fatta in p.Direction()
// Senza la normalize il bordo e' pesato in funzione della grandezza della mesh (mesh grandi non decimano sul bordo)
pb . SetDirection ( p . Direction ( ) ^ ( ( * pf ) . V1 ( j ) - > cP ( ) - ( * pf ) . V ( j ) - > cP ( ) ) . Normalize ( ) ) ;
2008-07-15 09:15:18 +02:00
if ( ( * pf ) . IsB ( j ) ) pb . SetDirection ( pb . Direction ( ) * ( ScalarType ) Params ( ) . BoundaryWeight ) ; // amplify border planes
else pb . SetDirection ( pb . Direction ( ) * ( ScalarType ) ( Params ( ) . BoundaryWeight / 100.0 ) ) ; // and consider much less quadric for quality
2004-09-15 12:25:20 +02:00
pb . SetOffset ( pb . Direction ( ) * ( * pf ) . V ( j ) - > cP ( ) ) ;
q . ByPlane ( pb ) ;
2006-10-09 22:12:55 +02:00
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 ;
2004-09-15 12:25:20 +02:00
}
}
if ( Params ( ) . ScaleIndependent )
{
vcg : : tri : : UpdateBounding < TriMeshType > : : Box ( m ) ;
//Make all quadric independent from mesh size
Params ( ) . ScaleFactor = 1e8 * pow ( 1.0 / m . bbox . Diag ( ) , 6 ) ; // scaling factor
//Params().ScaleFactor *=Params().ScaleFactor ;
//Params().ScaleFactor *=Params().ScaleFactor ;
//printf("Scale factor =%f\n",Params().ScaleFactor );
//printf("bb (%5.2f %5.2f %5.2f)-(%5.2f %5.2f %5.2f) Diag %f\n",m.bbox.min[0],m.bbox.min[1],m.bbox.min[2],m.bbox.max[0],m.bbox.max[1],m.bbox.max[2],m.bbox.Diag());
}
if ( Params ( ) . ComplexCheck )
{
// secondo loop per diminuire quadriche complex (se non c'erano i complex si poteva fare in un giro solo)
//for(pf=m.face.begin();pf!=m.face.end();++pf)
//if( !(*pf).IsD() && (*pf).IsR() )
// if((*pf).V(0)->IsR() &&(*pf).V(1)->IsR() &&(*pf).V(2)->IsR())
// {
// for(j=0;j<3;++j)
// if((*pf).IsCF(j)) // Complex!
// {
// if( (*pf).V (j)->IsW() ) (*pf).V (j)->q *= 0.01; // Scalo le quadriche
// if( (*pf).V1(j)->IsW() ) (*pf).V1(j)->q *= 0.01;
// }
// }
}
}
//
//
//
//
//
//
//static void InitMesh(MESH_TYPE &m){
// Params().CosineThr=cos(Params().NormalThr);
// InitQuadric(m);
// //m.Topology();
// //OldInitQuadric(m,UseArea);
// }
//
CoordType ComputeMinimal ( )
{
typename TriMeshType : : VertexType * v [ 2 ] ;
2005-04-14 13:35:09 +02:00
v [ 0 ] = this - > pos . V ( 0 ) ;
v [ 1 ] = this - > pos . V ( 1 ) ;
2006-10-09 22:12:55 +02:00
QuadricType q = QH : : Qd ( v [ 0 ] ) ;
q + = QH : : Qd ( v [ 1 ] ) ;
2004-09-15 12:25:20 +02:00
2006-10-09 22:12:55 +02:00
Point3 < QuadricType : : ScalarType > x ;
2007-03-22 12:07:16 +01:00
2006-10-09 22:12:55 +02:00
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.
2007-03-22 12:07:16 +01:00
Point3 < QuadricType : : ScalarType > x0 = Point3d : : Construct ( v [ 0 ] - > P ( ) ) ;
Point3 < QuadricType : : ScalarType > x1 = Point3d : : Construct ( v [ 1 ] - > P ( ) ) ;
x . Import ( ( v [ 0 ] - > P ( ) + v [ 1 ] - > P ( ) ) / 2 ) ;
2004-09-15 12:25:20 +02:00
double qvx = q . Apply ( x ) ;
2007-03-22 12:07:16 +01:00
double qv0 = q . Apply ( x0 ) ;
double qv1 = q . Apply ( x1 ) ;
if ( qv0 < qvx ) x = x0 ;
if ( qv1 < qvx & & qv1 < qv0 ) x = x1 ;
2004-09-15 12:25:20 +02:00
}
2006-10-09 22:12:55 +02:00
return CoordType : : Construct ( x ) ;
2004-09-15 12:25:20 +02:00
}
//
//
} ;
} // namespace tri
} // namespace vcg
# endif