1725 lines
42 KiB
C++
1725 lines
42 KiB
C++
/****************************************************************************
|
||
* VCGLib o o *
|
||
* Visual and Computer Graphics Library o o *
|
||
* _ O _ *
|
||
* Copyright(C) 2004 \/)\/ *
|
||
* Visual Computing Lab /\/| *
|
||
* ISTI - Italian National Research Council | *
|
||
* \ *
|
||
* All rights reserved. *
|
||
* *
|
||
* This program is free software; you can redistribute it and/or modify *
|
||
* it under the terms of the GNU General Public License as published by *
|
||
* the Free Software Foundation; either version 2 of the License, or *
|
||
* (at your option) any later version. *
|
||
* *
|
||
* This program is distributed in the hope that it will be useful, *
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||
* for more details. *
|
||
* *
|
||
****************************************************************************/
|
||
/****************************************************************************
|
||
History
|
||
|
||
$Log: not supported by cvs2svn $
|
||
Revision 1.1 2004/02/10 01:11:28 cignoni
|
||
Edited Comments and GPL license
|
||
|
||
****************************************************************************/
|
||
|
||
|
||
|
||
|
||
#ifndef FACE_TYPE
|
||
#pragma message("\nYou should never directly include this file\n")
|
||
#else
|
||
/* People should subclass his vertex class from this one... */
|
||
#include <assert.h>
|
||
#include <vcg/utility.h>
|
||
#include <vcg/Mesh/MeshPos.h>
|
||
|
||
#include <vcg/Point3.h>
|
||
#include <vcg/Line3.h>
|
||
#include <vcg/Plane3.h>
|
||
#include <vcg/Box3.h>
|
||
#include <vcg/tools/ColorUB.h>
|
||
|
||
namespace vcg {
|
||
|
||
/** @name Face
|
||
Class Face.
|
||
This is the base class for definition of a face of the mesh.
|
||
@param FVTYPE (Templete Parameter) Specifies the vertex class type.
|
||
*/
|
||
template <class FVTYPE, class TCTYPE = TCoord<float,1> > class FACE_TYPE
|
||
{
|
||
public:
|
||
typedef typename FVTYPE::face_type face_from_vert_type;
|
||
typedef typename FVTYPE::scalar_type FCTYPE;
|
||
/// The type of the scalar field of the vertex coordinate
|
||
typedef FCTYPE scalar_type;
|
||
/// The type of the the vertex coordinate
|
||
typedef Point3< FCTYPE > vectorial_type;
|
||
/// The base type of the face
|
||
typedef FACE_TYPE face_base;
|
||
/// The vertex type
|
||
typedef FVTYPE vertex_type;
|
||
/// The bounding box type
|
||
typedef Box3<scalar_type> bbox_type;
|
||
/// The texture coordiante type
|
||
typedef TCTYPE texcoord_type;
|
||
|
||
|
||
protected:
|
||
/// Vector of vertex pointer incident in the face
|
||
FVTYPE *v[3];
|
||
/// This are the flags of face, the default value is 0
|
||
int flags;
|
||
|
||
|
||
/*#*******************
|
||
* Quality *
|
||
**********************/
|
||
|
||
#ifdef __VCGLIB_FACE_Q
|
||
protected:
|
||
float quality;
|
||
#endif
|
||
public:
|
||
float & Q()
|
||
{
|
||
#ifdef __VCGLIB_FACE_Q
|
||
return quality;
|
||
#else
|
||
assert(0);
|
||
return *(float*)(&flags);
|
||
#endif
|
||
}
|
||
|
||
const float & Q() const
|
||
{
|
||
#ifdef __VCGLIB_FACE_Q
|
||
return quality;
|
||
#else
|
||
assert(0);
|
||
return *(float*)(&flags);
|
||
#endif
|
||
}
|
||
|
||
/*#*******************
|
||
* Texture *
|
||
**********************/
|
||
|
||
#ifdef __VCGLIB_FACE_T
|
||
TCTYPE t;
|
||
#endif
|
||
public:
|
||
TCTYPE & T()
|
||
{
|
||
#ifdef __VCGLIB_FACE_T
|
||
return t;
|
||
#else
|
||
assert(0);
|
||
return *(TCTYPE*)(&flags);
|
||
#endif
|
||
}
|
||
|
||
const TCTYPE & T() const
|
||
{
|
||
#ifdef __VCGLIB_FACE_T
|
||
return t;
|
||
#else
|
||
assert(0);
|
||
return *(TCTYPE*)(&flags);
|
||
#endif
|
||
}
|
||
|
||
// Per Wedge Texture Coords
|
||
protected:
|
||
#ifdef __VCGLIB_FACE_WT
|
||
TCTYPE wt[3];
|
||
#endif
|
||
public:
|
||
TCTYPE & WT(const int i)
|
||
{
|
||
#ifdef __VCGLIB_FACE_WT
|
||
return wt[i];
|
||
#else
|
||
assert(0);
|
||
return *(TCTYPE*)(&flags);
|
||
#endif
|
||
}
|
||
|
||
const TCTYPE & WT(const int i) const
|
||
{
|
||
#ifdef __VCGLIB_FACE_WT
|
||
return wt[i];
|
||
#else
|
||
assert(0);
|
||
return *(TCTYPE*)(&flags);
|
||
#endif
|
||
}
|
||
|
||
|
||
/*#*******************
|
||
* Colori *
|
||
**********************/
|
||
protected:
|
||
#ifdef __VCGLIB_FACE_C
|
||
ColorUB c;
|
||
#endif
|
||
|
||
public:
|
||
ColorUB & C()
|
||
{
|
||
#ifdef __VCGLIB_FACE_C
|
||
return c;
|
||
#else
|
||
assert(0);
|
||
return *(ColorUB*)(&flags);
|
||
#endif
|
||
}
|
||
|
||
const ColorUB C() const
|
||
{
|
||
#ifdef __VCGLIB_FACE_C
|
||
return c;
|
||
#else
|
||
return ColorUB(ColorUB::White);
|
||
#endif
|
||
}
|
||
|
||
protected:
|
||
#ifdef __VCGLIB_FACE_WC
|
||
ColorUB wc[3];
|
||
#endif
|
||
public:
|
||
ColorUB & WC(const int i)
|
||
{
|
||
#ifdef __VCGLIB_FACE_WC
|
||
return wc[i];
|
||
#else
|
||
assert(0);
|
||
return *(ColorUB*)(&flags);
|
||
#endif
|
||
}
|
||
|
||
const ColorUB WC(const int i) const
|
||
{
|
||
#ifdef __VCGLIB_FACE_WC
|
||
return wc[i];
|
||
#else
|
||
assert(0);
|
||
return ColorUB(ColorUB::White);
|
||
#endif
|
||
}
|
||
|
||
|
||
/*#*******************
|
||
* Normals *
|
||
**********************/
|
||
protected:
|
||
#ifdef __VCGLIB_FACE_N
|
||
/// This vector indicates the normal of the face (defines if FACE_N is defined)
|
||
vectorial_type n;
|
||
#endif
|
||
|
||
#ifdef __VCGLIB_FACE_WN
|
||
/// This vector indicates per wedge normal
|
||
vectorial_type wn[3];
|
||
#endif
|
||
|
||
public:
|
||
vectorial_type & WN(const int i)
|
||
{
|
||
#ifdef __VCGLIB_FACE_WN
|
||
return wn[i];
|
||
#else
|
||
assert(0);
|
||
return *(vectorial_type *)(&flags);
|
||
#endif
|
||
}
|
||
|
||
const vectorial_type & WN(const int i) const
|
||
{
|
||
#ifdef __VCGLIB_FACE_WN
|
||
return wn[i];
|
||
#else
|
||
return vectorial_type();
|
||
#endif
|
||
}
|
||
protected:
|
||
|
||
/*#*******************
|
||
* Adjacency data *
|
||
**********************/
|
||
#if (defined(__VCGLIB_FACE_A) && defined(__VCGLIB_FACE_S))
|
||
#error Error: You cannot specify face-to-face and shared topology together
|
||
#endif
|
||
|
||
#if (defined(__VCGLIB_FACE_V) && defined(__VCGLIB_FACE_S))
|
||
#error Error: You cannot specify vertex-face and shared topology together
|
||
#endif
|
||
|
||
|
||
#if defined(__VCGLIB_FACE_A)
|
||
/// Vector of face pointer, it's used to indicate the adjacency relations (defines if FACE_A is defined)
|
||
FACE_TYPE *ff[3]; // Facce adiacenti
|
||
/// Index of the face in the arrival face
|
||
char zf[4];
|
||
#endif
|
||
|
||
#ifdef __VCGLIB_FACE_V
|
||
///Vettore di puntatori a faccia, utilizzato per indicare le adiacenze vertice faccia
|
||
FACE_TYPE *fv[3];
|
||
char zv[3];
|
||
#endif
|
||
|
||
#ifdef __VCGLIB_FACE_S
|
||
///Vettore di puntatori a faccia, utilizzato per indicare le adiacenze vertice faccia
|
||
FACE_TYPE *fs[3];
|
||
char zs[3];
|
||
#endif
|
||
|
||
#ifdef __VCGLIB_FACE_M
|
||
/// Incremental mark (defines if FACE_I is defined)
|
||
int imark;
|
||
#endif // Mark
|
||
|
||
|
||
public:
|
||
enum {
|
||
OBJ_TYPE_A = 0x0001,
|
||
OBJ_TYPE_N = 0x0002,
|
||
OBJ_TYPE_M = 0x0004,
|
||
OBJ_TYPE_V = 0x0008,
|
||
OBJ_TYPE_S = 0x0010,
|
||
OBJ_TYPE_E = 0x0020,
|
||
OBJ_TYPE_C = 0x0040,
|
||
OBJ_TYPE_WN = 0x0080,
|
||
OBJ_TYPE_WC = 0x0100,
|
||
OBJ_TYPE_WT = 0x0200,
|
||
OBJ_TYPE_Q = 0x0400,
|
||
};
|
||
|
||
enum {
|
||
OBJ_TYPE =
|
||
#ifdef __VCGLIB_FACE_A
|
||
OBJ_TYPE_A |
|
||
#endif
|
||
#ifdef __VCGLIB_FACE_N
|
||
OBJ_TYPE_N |
|
||
#endif
|
||
#ifdef __VCGLIB_FACE_M
|
||
OBJ_TYPE_M |
|
||
#endif
|
||
#ifdef __VCGLIB_FACE_V
|
||
OBJ_TYPE_V |
|
||
#endif
|
||
#ifdef __VCGLIB_FACE_S
|
||
OBJ_TYPE_S |
|
||
#endif
|
||
#ifdef __VCGLIB_FACE_E
|
||
OBJ_TYPE_E |
|
||
#endif
|
||
#ifdef __VCGLIB_FACE_C
|
||
OBJ_TYPE_C |
|
||
#endif
|
||
#ifdef __VCGLIB_FACE_WN
|
||
OBJ_TYPE_WN |
|
||
#endif
|
||
#ifdef __VCGLIB_FACE_WC
|
||
OBJ_TYPE_WC |
|
||
#endif
|
||
#ifdef __VCGLIB_FACE_WT
|
||
OBJ_TYPE_WT |
|
||
#endif
|
||
#ifdef __VCGLIB_FACE_Q
|
||
OBJ_TYPE_Q |
|
||
#endif
|
||
0
|
||
};
|
||
|
||
enum {
|
||
// This bit indicate that the face is deleted from the mesh
|
||
DELETED = 0x00000001, // cancellato
|
||
// This bit indicate that the face of the mesh is not readable
|
||
NOTREAD = 0x00000002, // non leggibile (ma forse modificabile)
|
||
// This bit indicate that the face is not modifiable
|
||
NOTWRITE = 0x00000004, // non modificabile (ma forse leggibile)
|
||
// This bit indicate that the face is modified
|
||
MODIFIED = 0x00000008, // modificato
|
||
// This bit can be used to mark the visited face
|
||
VISITED = 0x00000010, // Visited
|
||
// This bit can be used to select
|
||
SELECTED = 0x00000020, // Selection flags
|
||
// Border flags, it is assumed that BORDERi = BORDER0<<i
|
||
BORDER0 = 0x00000040,
|
||
BORDER1 = 0x00000080,
|
||
BORDER2 = 0x00000100,
|
||
// Face Orientation Flags, used efficiently compute point face distance
|
||
NORMX = 0x00000200,
|
||
NORMY = 0x00000400,
|
||
NORMZ = 0x00000800,
|
||
// Complex flags, it is assumed that BORDERi = BORDER0<<i
|
||
COMPLEX0 = 0x00001000,
|
||
COMPLEX1 = 0x00002000,
|
||
COMPLEX2 = 0x00004000,
|
||
// Crease flags, it is assumed that FEATUREi = FEATURE0<<i
|
||
FEATURE0 = 0x00008000,
|
||
FEATURE1 = 0x00010000,
|
||
FEATURE2 = 0x00020000,
|
||
// Flags per Marcatura degli halfedge
|
||
MHEDGE0 = 0x00040000,
|
||
MHEDGE1 = 0x00080000,
|
||
MHEDGE2 = 0x00100000,
|
||
// First user bit
|
||
USER0 = 0x00040000
|
||
};
|
||
|
||
static int &LastBitFlag()
|
||
{
|
||
static int b =USER0;
|
||
return b;
|
||
}
|
||
static inline int NewBitFlag()
|
||
{
|
||
LastBitFlag()=LastBitFlag()<<1;
|
||
return LastBitFlag();
|
||
}
|
||
static inline bool DeleteBitFlag(int bitval)
|
||
{
|
||
if(LastBitFlag()==bitval) {
|
||
LastBitFlag()= LastBitFlag()>>1;
|
||
return true;
|
||
}
|
||
assert(0);
|
||
return false;
|
||
}
|
||
|
||
inline FACE_TYPE() {
|
||
/*
|
||
#ifdef _DEBUG
|
||
flags=0;
|
||
#ifdef __VCGLIB_FACE_A
|
||
f[0]=f[1]=f[2]=0;
|
||
#endif
|
||
|
||
#endif
|
||
*/
|
||
};
|
||
|
||
/*#*******************
|
||
* Bounding box *
|
||
**********************/
|
||
|
||
void GetBBox( bbox_type & bb )
|
||
{
|
||
bb.Set( v[0]->P() );
|
||
bb.Add( v[1]->P() );
|
||
bb.Add( v[2]->P() );
|
||
}
|
||
|
||
/// Return the number of vertices of the face
|
||
int size() const {return 3;}
|
||
|
||
/** Return the pointer to the j-th vertex of the face.
|
||
@param j Index of the face vertex.
|
||
*/
|
||
inline FVTYPE * & V( const int j )
|
||
{
|
||
assert( (flags & DELETED) == 0 );
|
||
assert( (flags & NOTREAD) == 0 );
|
||
assert( (flags & NOTWRITE) == 0 );
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
return v[j];
|
||
}
|
||
|
||
inline const FVTYPE * const & V( const int j ) const
|
||
{
|
||
assert( (flags & DELETED) == 0 );
|
||
assert( (flags & NOTREAD) == 0 );
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
return v[j];
|
||
}
|
||
inline const FVTYPE * const & cV( const int j ) const
|
||
{
|
||
assert( (flags & DELETED) == 0 );
|
||
assert( (flags & NOTREAD) == 0 );
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
return v[j];
|
||
}
|
||
|
||
// Shortcut per accedere ai punti delle facce
|
||
inline vectorial_type & P( const int j )
|
||
{
|
||
assert( (flags & DELETED) == 0 );
|
||
assert( (flags & NOTREAD) == 0 );
|
||
assert( (flags & NOTWRITE) == 0 );
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
return v[j]->P();
|
||
}
|
||
|
||
inline const vectorial_type & P( const int j ) const
|
||
{
|
||
assert( (flags & DELETED) == 0 );
|
||
assert( (flags & NOTREAD) == 0 );
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
return v[j]->cP();
|
||
}
|
||
inline const vectorial_type & cP( const int j ) const
|
||
{
|
||
assert( (flags & DELETED) == 0 );
|
||
assert( (flags & NOTREAD) == 0 );
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
return v[j]->cP();
|
||
}
|
||
|
||
/** Return the pointer to the ((j+1)%3)-th vertex of the face.
|
||
@param j Index of the face vertex.
|
||
*/
|
||
inline FVTYPE * & V0( const int j ) { return V(j);}
|
||
inline FVTYPE * & V1( const int j ) { return V((j+1)%3);}
|
||
inline FVTYPE * & V2( const int j ) { return V((j+2)%3);}
|
||
inline const FVTYPE * const & V0( const int j ) const { return V(j);}
|
||
inline const FVTYPE * const & V1( const int j ) const { return V((j+1)%3);}
|
||
inline const FVTYPE * const & V2( const int j ) const { return V((j+2)%3);}
|
||
inline const FVTYPE * const & cV0( const int j ) const { return cV(j);}
|
||
inline const FVTYPE * const & cV1( const int j ) const { return cV((j+1)%3);}
|
||
inline const FVTYPE * const & cV2( const int j ) const { return cV((j+2)%3);}
|
||
|
||
// Shortcut per accedere ai punti delle facce
|
||
inline vectorial_type & P0( const int j ) { return V(j)->P();}
|
||
inline vectorial_type & P1( const int j ) { return V((j+1)%3)->P();}
|
||
inline vectorial_type & P2( const int j ) { return V((j+2)%3)->P();}
|
||
inline const vectorial_type & P0( const int j ) const { return V(j)->P();}
|
||
inline const vectorial_type & P1( const int j ) const { return V((j+1)%3)->P();}
|
||
inline const vectorial_type & P2( const int j ) const { return V((j+2)%3)->P();}
|
||
inline const vectorial_type & cP0( const int j ) const { return cV(j)->P();}
|
||
inline const vectorial_type & cP1( const int j ) const { return cV((j+1)%3)->P();}
|
||
inline const vectorial_type & cP2( const int j ) const { return cV((j+2)%3)->P();}
|
||
|
||
inline FVTYPE * & Supervisor_V( const int j )
|
||
{
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
return v[j];
|
||
}
|
||
|
||
inline const FVTYPE * const & Supervisor_V( const int j ) const
|
||
{
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
return v[j];
|
||
}
|
||
|
||
/// Return the flags.
|
||
inline int & Flags ()
|
||
{
|
||
assert( (flags & DELETED) == 0 );
|
||
assert( (flags & NOTREAD) == 0 );
|
||
return flags;
|
||
}
|
||
|
||
inline const int & Flags () const
|
||
{
|
||
assert( (flags & DELETED) == 0 );
|
||
assert( (flags & NOTREAD) == 0 );
|
||
return flags;
|
||
}
|
||
/// Ritorna il flags senza effettuare alcun controllo sui relativi bit
|
||
inline int & Supervisor_Flags()
|
||
{
|
||
return flags;
|
||
}
|
||
|
||
inline const int Supervisor_Flags() const
|
||
{
|
||
return flags;
|
||
}
|
||
|
||
/// Return the reference of the normal to the face (if __VCGLIB_FACE_N is defined).
|
||
inline vectorial_type & N()
|
||
{
|
||
#ifdef __VCGLIB_FACE_N
|
||
return n;
|
||
#else
|
||
assert(0);
|
||
return *(vectorial_type *)0;
|
||
#endif
|
||
}
|
||
/// Return the reference of the normal to the face (if __VCGLIB_FACE_N is defined).
|
||
inline const vectorial_type & N() const
|
||
{
|
||
#ifdef __VCGLIB_FACE_N
|
||
return n;
|
||
#else
|
||
return vcg::Normal(V(0)->P(), V(1)->P(), V(2)->P());
|
||
#endif
|
||
}
|
||
/// Return the reference of the normal to the face (if __VCGLIB_FACE_N is defined).
|
||
inline const vectorial_type cN() const
|
||
{
|
||
return Normal();
|
||
}
|
||
|
||
/** Return the pointer to the j-th adjacent face.
|
||
@param j Index of the edge.
|
||
*/
|
||
inline FACE_TYPE * & F( const int j )
|
||
{
|
||
assert( (flags & DELETED) == 0 );
|
||
assert( (flags & NOTREAD) == 0 );
|
||
assert( (flags & NOTWRITE) == 0 );
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
#if defined(__VCGLIB_FACE_A)
|
||
return ff[j];
|
||
#elif defined(__VCGLIB_FACE_S)
|
||
return fs[j];
|
||
#else
|
||
assert(0);
|
||
static FACE_TYPE *dum=0;
|
||
return dum;
|
||
#endif
|
||
}
|
||
|
||
inline const FACE_TYPE * const & F( const int j ) const
|
||
{
|
||
assert( (flags & DELETED) == 0 );
|
||
assert( (flags & NOTREAD) == 0 );
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
#if defined(__VCGLIB_FACE_A)
|
||
return ff[j];
|
||
#elif defined(__VCGLIB_FACE_S)
|
||
return fs[j];
|
||
#else
|
||
assert(0);
|
||
return (FACE_TYPE *)this;
|
||
#endif
|
||
}
|
||
inline FACE_TYPE * & F1( const int j ) { return F((j+1)%3);}
|
||
inline FACE_TYPE * & F2( const int j ) { return F((j+2)%3);}
|
||
inline const FACE_TYPE * const& F1( const int j ) const { return F((j+1)%3);}
|
||
inline const FACE_TYPE * const& F2( const int j ) const { return F((j+2)%3);}
|
||
|
||
|
||
/** Return the pointer to the j-th adjacent face.
|
||
@param j Index of the edge.
|
||
*/
|
||
inline FACE_TYPE * & Supervisor_F( const int j )
|
||
{
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
#if defined(__VCGLIB_FACE_A)
|
||
return ff[j];
|
||
#elif defined(__VCGLIB_FACE_S)
|
||
return fs[j];
|
||
#else
|
||
assert(0); // if you stop here you are probably trying to use FF topology in a face without it
|
||
return *((FACE_TYPE **)(flags));
|
||
#endif
|
||
}
|
||
|
||
inline const FACE_TYPE * const & Supervisor_F( const int j ) const
|
||
{
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
#if defined(__VCGLIB_FACE_A)
|
||
return ff[j];
|
||
#elif defined(__VCGLIB_FACE_S)
|
||
return fs[j];
|
||
#else
|
||
assert(0); // if you stop here you are probably trying to use FF topology in a face without it
|
||
return *((FACE_TYPE **)(flags));
|
||
#endif
|
||
}
|
||
|
||
|
||
inline FACE_TYPE * & Fv( const int j )
|
||
{
|
||
assert( (flags & DELETED) == 0 );
|
||
assert( (flags & NOTREAD) == 0 );
|
||
assert( (flags & NOTWRITE) == 0 );
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
#ifdef __VCGLIB_FACE_V
|
||
return fv[j];
|
||
#elif defined(__VCGLIB_FACE_S)
|
||
return fs[j];
|
||
#else
|
||
assert(0); // you are probably trying to use VF topology in a vertex without it
|
||
return *((FACE_TYPE **)(flags));
|
||
#endif
|
||
}
|
||
|
||
inline const FACE_TYPE * const & Fv( const int j ) const
|
||
{
|
||
assert( (flags & DELETED) == 0 );
|
||
assert( (flags & NOTREAD) == 0 );
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
#ifdef __VCGLIB_FACE_V
|
||
return fv[j];
|
||
#elif defined(__VCGLIB_FACE_S)
|
||
return fs[j];
|
||
#else
|
||
assert(0);
|
||
return (FACE_TYPE *)this;
|
||
#endif
|
||
}
|
||
|
||
|
||
/** Return the index that the face have in the j-th adjacent face.
|
||
@param j Index of the edge.
|
||
*/
|
||
inline char & Z( const int j )
|
||
{
|
||
assert( (flags & DELETED) == 0 );
|
||
assert( (flags & NOTREAD) == 0 );
|
||
assert( (flags & NOTWRITE) == 0 );
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
#if defined(__VCGLIB_FACE_A)
|
||
return zf[j];
|
||
#elif defined(__VCGLIB_FACE_S)
|
||
return zs[j];
|
||
#else
|
||
assert(0);
|
||
return *(char *)&flags; // tanto per farlo compilare...
|
||
#endif
|
||
}
|
||
|
||
inline const char & Z( const int j ) const
|
||
{
|
||
assert( (flags & DELETED) == 0 );
|
||
assert( (flags & NOTREAD) == 0 );
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
#if defined(__VCGLIB_FACE_A)
|
||
return zf[j];
|
||
#elif defined(__VCGLIB_FACE_S)
|
||
return zs[j];
|
||
#else
|
||
assert(0);
|
||
return *(char *)&flags;
|
||
#endif
|
||
}
|
||
|
||
/** Return the index that the face have in the j-th adjacent face.
|
||
@param j Index of the edge.
|
||
*/
|
||
inline char & Supervisor_Z( const int j )
|
||
{
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
#if defined(__VCGLIB_FACE_A)
|
||
return zf[j];
|
||
#elif defined(__VCGLIB_FACE_S)
|
||
return zs[j];
|
||
#else
|
||
assert(0);
|
||
return *(char *)&flags;
|
||
#endif
|
||
}
|
||
|
||
inline const char & Supervisor_Z( const int j ) const
|
||
{
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
#if defined(__VCGLIB_FACE_A)
|
||
return zf[j];
|
||
#elif defined(__VCGLIB_FACE_S)
|
||
return zs[j];
|
||
#else
|
||
assert(0);
|
||
return *(char *)&flags;
|
||
#endif
|
||
}
|
||
|
||
|
||
inline char & Zv( const int j )
|
||
{
|
||
assert( (flags & DELETED) == 0 );
|
||
assert( (flags & NOTREAD) == 0 );
|
||
assert( (flags & NOTWRITE) == 0 );
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
#ifdef __VCGLIB_FACE_V
|
||
return zv[j];
|
||
#elif defined(__VCGLIB_FACE_S)
|
||
return zs[j];
|
||
#else
|
||
assert(0);
|
||
return *(char *)&flags;
|
||
#endif
|
||
}
|
||
|
||
inline const char & Zv( const int j ) const
|
||
{
|
||
assert( (flags & DELETED) == 0 );
|
||
assert( (flags & NOTREAD) == 0 );
|
||
assert(j>=0);
|
||
assert(j<size());
|
||
#ifdef __VCGLIB_FACE_V
|
||
return zv[j];
|
||
#elif defined(__VCGLIB_FACE_S)
|
||
return zs[j];
|
||
#else
|
||
assert(0);
|
||
return *(char *)&flags;
|
||
#endif
|
||
}
|
||
|
||
//#endif
|
||
|
||
/* non posso usare vettori di facce
|
||
inline FVTYPE * & operator [] ( const int i ){
|
||
assert(i>=0 && i<3);
|
||
return v[i];
|
||
}
|
||
inline const FVTYPE * & operator [] ( const int i ) const {
|
||
assert(i>=0 && i<3);
|
||
return v[i];
|
||
}
|
||
*/
|
||
|
||
/// operator to compare two faces
|
||
inline bool operator == ( const FACE_TYPE & f ) const {
|
||
for(int i=0; i<size(); ++i)
|
||
if( (V(i) != f.V(0)) && (V(i) != f.V(1)) && (V(i) != f.V(2)) )
|
||
return false;
|
||
return true;
|
||
}
|
||
|
||
|
||
/*inline bool operator < ( const FACE_TYPE & f ) const {
|
||
}*/
|
||
|
||
|
||
|
||
/// This function checks if the face is deleted
|
||
bool IsD() const {return (flags & DELETED) != 0;}
|
||
/// This function mark the face as deleted
|
||
void SetD() {flags |=DELETED;}
|
||
/// This function mark the face as not deleted
|
||
void ClearD() {flags &= (~DELETED);}
|
||
/// This function checks if the face is deleted
|
||
bool IsDeleted() const {return IsD();}
|
||
|
||
/// This function checks if the face is readable
|
||
bool IsR() const {return (flags & NOTREAD) == 0;}
|
||
/// This function marks the face as readable
|
||
void SetR() {flags &= (~NOTREAD);}
|
||
/// This function marks the face as not readable
|
||
void ClearR() {flags |=NOTREAD;}
|
||
/// This function checks if the face is readable
|
||
bool IsReadable() const {return IsR();}
|
||
|
||
/// This function checks if the face is readable
|
||
bool IsW() const {return (flags & NOTWRITE)== 0;}
|
||
/// This function marks the vertex as not writable
|
||
void SetW() {flags &=(~NOTWRITE);}
|
||
/// This function marks the face as not writable
|
||
void ClearW() {flags |=NOTWRITE;}
|
||
|
||
/// This function checks if the face is modifiable
|
||
bool IsWritable() const {return IsW();}
|
||
/// This funcion checks whether the face is both readable and modifiable
|
||
bool IsRW() const {return (flags & (NOTREAD | NOTWRITE)) == 0;}
|
||
|
||
/// This function checks if the face is Modified
|
||
bool IsM() const {return (flags & MODIFIED)!= 0;}
|
||
/// This function marks the face as modified. It's necessary to mark all modified faces to have a consistent mesh
|
||
void SetM() {flags |=MODIFIED;}
|
||
/// This function marks the face as not visited. This flag, initially, is setted to random value, therefore, to the beginnig of every function it is necessary to clean up the flag
|
||
void ClearM() {flags &= (~MODIFIED);}
|
||
|
||
/// This function checks if the face is marked as visited
|
||
bool IsV() const {return (flags & VISITED)!= 0;}
|
||
/// This funcion marks the face as visited
|
||
void SetV() {flags |=VISITED;}
|
||
/// This function marks the face as not visited. This flag, initially, is setted to random value, therefore, to the beginnig of every function it is necessary to clean up the flag
|
||
void ClearV() {flags &= (~VISITED);}
|
||
|
||
/// This function checks if the face is selected
|
||
bool IsS() const {return (flags & SELECTED) != 0;}
|
||
/// This function select the face
|
||
void SetS() {flags |=SELECTED;}
|
||
/// This funcion execute the inverse operation of SetS()
|
||
void ClearS() {flags &= (~SELECTED);}
|
||
|
||
/// This function checks if the face is selected
|
||
bool IsB(int i) const {return (flags & (BORDER0<<i)) != 0;}
|
||
/// This function select the face
|
||
void SetB(int i) {flags |=(BORDER0<<i);}
|
||
/// This funcion execute the inverse operation of SetS()
|
||
void ClearB(int i) {flags &= (~(BORDER0<<i));}
|
||
|
||
/// This function checks if the face is Complex on side i
|
||
bool IsCF(int i) const {return (flags & (COMPLEX0<<i)) != 0;}
|
||
/// This function select the face
|
||
void SetCF(int i) {flags |=(COMPLEX0<<i);}
|
||
/// This funcion execute the inverse operation of SetS()
|
||
void ClearCF(int i) {flags &= (~(COMPLEX0<<i));}
|
||
|
||
/// This function checks if the face is Crease on side i
|
||
bool IsFF(int i) const {return (flags & (FEATURE0<<i)) != 0;}
|
||
/// This function select the face flag
|
||
void SetFF(int i) {flags |=(FEATURE0<<i);}
|
||
/// This funcion execute the inverse operation of Set()
|
||
void ClearFF(int i) {flags &= (~(FEATURE0<<i));}
|
||
|
||
/// This function checks if the half edge i is marked
|
||
bool IsHEdgeM(int i) const {return (flags & (MHEDGE0<<i)) != 0;}
|
||
/// This function set the half edge mark
|
||
void SetHEdgeM(int i) {flags |=(MHEDGE0<<i);}
|
||
/// This funcion execute the inverse operation of the previuse one
|
||
void ClearHEdgeM(int i) {flags &= (~(MHEDGE0<<i));}
|
||
|
||
/// This function checks if the given user bit is true
|
||
bool IsUserBit(int userBit){return (flags & userBit) != 0;}
|
||
/// This function set the given user bit
|
||
void SetUserBit(int userBit){flags |=userBit;}
|
||
/// This function clear the given user bit
|
||
void ClearUserBit(int userBit){flags &= (~userBit);}
|
||
|
||
/*#*******************
|
||
* Normals *
|
||
**********************/
|
||
/// Calculate the normal to the face, the value is store in the field n of the face
|
||
void ComputeNormal()
|
||
{
|
||
#ifdef __VCGLIB_FACE_N
|
||
n = vcg::Normal(V(0)->cP(), V(1)->cP(), V(2)->cP());
|
||
#else
|
||
assert(0);
|
||
#endif
|
||
}
|
||
void ComputeNormalizedNormal()
|
||
{
|
||
#ifdef __VCGLIB_FACE_N
|
||
n = vcg::NormalizedNormal(V(0)->cP(), V(1)->cP(), V(2)->cP());
|
||
#else
|
||
assert(0);
|
||
#endif
|
||
}
|
||
|
||
/// Return the value of the face normal; warning: if __VCGLIB_FACE_N is not defined the value is computed each time
|
||
vectorial_type Normal() const
|
||
{
|
||
#ifdef __VCGLIB_FACE_N
|
||
return n;
|
||
#else
|
||
return vcg::Normal(V(0)->P(), V(1)->P(), V(2)->P());
|
||
#endif
|
||
}
|
||
|
||
/** Calcola i coefficienti della combinazione convessa.
|
||
@param bq Punto appartenente alla faccia
|
||
@param a Valore di ritorno per il vertice V(0)
|
||
@param b Valore di ritorno per il vertice V(1)
|
||
@param c Valore di ritorno per il vertice V(2)
|
||
@return true se bq appartiene alla faccia, false altrimenti
|
||
*/
|
||
bool InterpolationParameters(const vectorial_type & bq, scalar_type &a, scalar_type &b, scalar_type &c ) const
|
||
{
|
||
/********** VECCHIA VERSIONE *********************
|
||
//Calcolo degli assi dominanti
|
||
int axis; // asse piu' perpendicolare alla faccia
|
||
scalar_type max;
|
||
vectorial_type fnorm = Normal();
|
||
max = Abs(fnorm[0]);
|
||
axis = 0;
|
||
if( max < Abs(fnorm[1]) )
|
||
{
|
||
max = Abs(fnorm[1]);
|
||
axis = 1;
|
||
}
|
||
if( max < Abs(fnorm[2]) )
|
||
{
|
||
max = Abs(fnorm[2]);
|
||
axis = 2;
|
||
}
|
||
|
||
scalar_type x[3];
|
||
scalar_type C[3][3+1];
|
||
|
||
C[0][0] = cV(0)->P()[(axis+1)%3];
|
||
C[0][1] = cV(1)->P()[(axis+1)%3];
|
||
C[0][2] = cV(2)->P()[(axis+1)%3];
|
||
C[0][3] = bq [(axis+1)%3];
|
||
|
||
C[1][0] = cV(0)->P()[(axis+2)%3];
|
||
C[1][1] = cV(1)->P()[(axis+2)%3];
|
||
C[1][2] = cV(2)->P()[(axis+2)%3];
|
||
C[1][3] = bq [(axis+2)%3];
|
||
|
||
C[2][0] = 1;
|
||
C[2][1] = 1;
|
||
C[2][2] = 1;
|
||
C[2][3] = 1;
|
||
|
||
if(Gauss33(x,C))
|
||
{
|
||
a=x[0];
|
||
b=x[1];
|
||
c=x[2];
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
a=b=c=1.0/3.0;
|
||
return false;
|
||
}
|
||
********** FINE VECCHIA VERSIONE ***************/
|
||
|
||
const scalar_type EPSILON = scalar_type(0.000001);
|
||
|
||
|
||
#define x1 (cV(0)->P().x())
|
||
#define y1 (cV(0)->P().y())
|
||
#define z1 (cV(0)->P().z())
|
||
#define x2 (cV(1)->P().x())
|
||
#define y2 (cV(1)->P().y())
|
||
#define z2 (cV(1)->P().z())
|
||
#define x3 (cV(2)->P().x())
|
||
#define y3 (cV(2)->P().y())
|
||
#define z3 (cV(2)->P().z())
|
||
#define px (bq.x())
|
||
#define py (bq.y())
|
||
#define pz (bq.z())
|
||
|
||
scalar_type t1 = px*y2;
|
||
scalar_type t2 = px*y3;
|
||
scalar_type t3 = py*x2;
|
||
scalar_type t4 = py*x3;
|
||
scalar_type t5 = x2*y3;
|
||
scalar_type t6 = x3*y2;
|
||
scalar_type t8 = x1*y2;
|
||
scalar_type t9 = x1*y3;
|
||
scalar_type t10 = y1*x2;
|
||
scalar_type t11 = y1*x3;
|
||
scalar_type t13 = t8-t9-t10+t11+t5-t6;
|
||
if(fabs(t13)>=EPSILON)
|
||
{
|
||
scalar_type t15 = px*y1;
|
||
scalar_type t16 = py*x1;
|
||
a = (t1 -t2-t3 +t4+t5-t6 )/t13;
|
||
b = -(t15-t2-t16+t4+t9-t11)/t13;
|
||
c = (t15-t1-t16+t3+t8-t10)/t13;
|
||
return true;
|
||
}
|
||
|
||
t1 = px*z2;
|
||
t2 = px*z3;
|
||
t3 = pz*x2;
|
||
t4 = pz*x3;
|
||
t5 = x2*z3;
|
||
t6 = x3*z2;
|
||
t8 = x1*z2;
|
||
t9 = x1*z3;
|
||
t10 = z1*x2;
|
||
t11 = z1*x3;
|
||
t13 = t8-t9-t10+t11+t5-t6;
|
||
if(fabs(t13)>=EPSILON)
|
||
{
|
||
scalar_type t15 = px*z1;
|
||
scalar_type t16 = pz*x1;
|
||
a = (t1 -t2-t3 +t4+t5-t6 )/t13;
|
||
b = -(t15-t2-t16+t4+t9-t11)/t13;
|
||
c = (t15-t1-t16+t3+t8-t10)/t13;
|
||
return true;
|
||
}
|
||
|
||
t1 = pz*y2; t2 = pz*y3;
|
||
t3 = py*z2; t4 = py*z3;
|
||
t5 = z2*y3; t6 = z3*y2;
|
||
t8 = z1*y2; t9 = z1*y3;
|
||
t10 = y1*z2; t11 = y1*z3;
|
||
t13 = t8-t9-t10+t11+t5-t6;
|
||
if(fabs(t13)>=EPSILON)
|
||
{
|
||
scalar_type t15 = pz*y1;
|
||
scalar_type t16 = py*z1;
|
||
a = (t1 -t2-t3 +t4+t5-t6 )/t13;
|
||
b = -(t15-t2-t16+t4+t9-t11)/t13;
|
||
c = (t15-t1-t16+t3+t8-t10)/t13;
|
||
return true;
|
||
}
|
||
|
||
#undef x1
|
||
#undef y1
|
||
#undef z1
|
||
#undef x2
|
||
#undef y2
|
||
#undef z2
|
||
#undef x3
|
||
#undef y3
|
||
#undef z3
|
||
#undef px
|
||
#undef py
|
||
#undef pz
|
||
|
||
return false;
|
||
}
|
||
|
||
|
||
/*#*******************
|
||
* Adjacency Members *
|
||
**********************/
|
||
|
||
|
||
/** Return a boolean that indicate if the face is complex.
|
||
@param j Index of the edge
|
||
@return true se la faccia e' manifold, false altrimenti
|
||
*/
|
||
inline bool IsManifold( const int j ) const
|
||
{
|
||
#if (defined(__VCGLIB_FACE_A) || defined(__VCGLIB_FACE_S))
|
||
return ( F(j)==this || this == F(j)->F(Z(j)) );
|
||
#endif
|
||
return true;
|
||
assert(0);
|
||
}
|
||
|
||
/** Return a boolean that indicate if the j-th edge of the face is a border.
|
||
@param j Index of the edge
|
||
@return true if j is an edge of border, false otherwise
|
||
*/
|
||
inline bool IsBorder( const int j ) const
|
||
{
|
||
#if (defined(__VCGLIB_FACE_A) || defined(__VCGLIB_FACE_S))
|
||
return F(j)==this;
|
||
#endif
|
||
return true;
|
||
assert(0);
|
||
}
|
||
|
||
|
||
/// This function counts the boreders of the face
|
||
inline int BorderCount() const
|
||
{
|
||
#if (defined(__VCGLIB_FACE_A) || defined(__VCGLIB_FACE_S))
|
||
int t = 0;
|
||
if( IsBorder(0) ) ++t;
|
||
if( IsBorder(1) ) ++t;
|
||
if( IsBorder(2) ) ++t;
|
||
return t;
|
||
#endif
|
||
assert(0);
|
||
return 3;
|
||
}
|
||
|
||
|
||
/// This function counts the number of incident faces in a complex edge
|
||
inline int ComplexSize(const int e) const
|
||
{
|
||
#if (defined(__VCGLIB_FACE_A) || defined(__VCGLIB_FACE_S))
|
||
int cnt=0;
|
||
FACE_TYPE *fi=(FACE_TYPE *)this;
|
||
int nzi,zi=e;
|
||
do
|
||
{
|
||
nzi=fi->Z(zi);
|
||
fi=fi->F(zi);
|
||
zi=nzi;
|
||
++cnt;
|
||
}
|
||
while(fi!=this);
|
||
return cnt;
|
||
#endif
|
||
assert(0);
|
||
return 2;
|
||
}
|
||
|
||
/*Funzione di detach che scollega una faccia da un ciclo
|
||
(eventualmente costituito da due soli elementi) incidente su un edge*/
|
||
/** This function detach the face from the adjacent face via the edge e. It's possible to use it also in non-two manifold situation.
|
||
The function cannot be applicated if the adjacencies among faces aren't define.
|
||
@param e Index of the edge
|
||
*/
|
||
void Detach(const int e)
|
||
{
|
||
typedef FEdgePosB< FACE_TYPE > ETYPE;
|
||
|
||
assert(!IsBorder(e));
|
||
ETYPE EPB(this,e); // la faccia dall'altra parte
|
||
EPB.NextF();
|
||
int cnt=0;
|
||
while ( EPB.f->F(EPB.z) != this)
|
||
{
|
||
assert(!IsManifold(e)); // Si entra in questo loop solo se siamo in una situazione non manifold.
|
||
assert(!EPB.f->IsBorder(EPB.z));
|
||
EPB.NextF();
|
||
cnt++;
|
||
}
|
||
assert(EPB.f->F(EPB.z)==this);
|
||
|
||
EPB.f->F(EPB.z) = F(e);
|
||
EPB.f->Z(EPB.z) = Z(e);
|
||
|
||
F(e) = this;
|
||
Z(e) = e;
|
||
|
||
EPB.f->SetM();
|
||
this->SetM();
|
||
}
|
||
|
||
void OldDetach(const int e)
|
||
{
|
||
typedef EdgePosB< FACE_TYPE > ETYPE;
|
||
|
||
assert(!IsBorder(e));
|
||
ETYPE EPB(this,e);
|
||
ETYPE TEPB(0,-1);
|
||
EPB.NextF();
|
||
while ( EPB.f != this)
|
||
{
|
||
TEPB = EPB;
|
||
assert(!EPB.f->IsBorder(EPB.z));
|
||
EPB.NextF();
|
||
}
|
||
assert(TEPB.f->F(TEPB.z)==this);
|
||
TEPB.f->F(TEPB.z) = F(e);
|
||
TEPB.f->Z(TEPB.z) = Z(e);
|
||
F(e) = this;
|
||
Z(e) = e;
|
||
TEPB.f->SetM();
|
||
this->SetM();
|
||
}
|
||
|
||
|
||
/** This function attach the face (via the edge z1) to another face (via the edge z2). It's possible to use it also in non-two manifold situation.
|
||
The function cannot be applicated if the adjacencies among faces aren't define.
|
||
@param z1 Index of the edge
|
||
@param f2 Pointer to the face
|
||
@param z2 The edge of the face f2
|
||
*/
|
||
void Attach(int z1, face_base *&f2, int z2)
|
||
{
|
||
typedef FEdgePosB< FACE_TYPE > ETYPE;
|
||
ETYPE EPB(f2,z2);
|
||
ETYPE TEPB;
|
||
TEPB = EPB;
|
||
EPB.NextF();
|
||
while( EPB.f != f2) //Alla fine del ciclo TEPB contiene la faccia che precede f2
|
||
{
|
||
TEPB = EPB;
|
||
EPB.NextF();
|
||
}
|
||
//Salvo i dati di f1 prima di sovrascrivere
|
||
face_base *f1prec = this->F(z1);
|
||
int z1prec = this->Z(z1);
|
||
//Aggiorno f1
|
||
this->F(z1) = TEPB.f->F(TEPB.z);
|
||
this->Z(z1) = TEPB.f->Z(TEPB.z);
|
||
//Aggiorno la faccia che precede f2
|
||
TEPB.f->F(TEPB.z) = f1prec;
|
||
TEPB.f->Z(TEPB.z) = z1prec;
|
||
}
|
||
|
||
|
||
void AssertAdj()
|
||
{
|
||
assert(F(0)->F(Z(0))==this);
|
||
assert(F(1)->F(Z(1))==this);
|
||
assert(F(2)->F(Z(2))==this);
|
||
|
||
assert(F(0)->Z(Z(0))==0);
|
||
assert(F(1)->Z(Z(1))==1);
|
||
assert(F(2)->Z(Z(2))==2);
|
||
}
|
||
//#endif // Adjacency
|
||
|
||
/*#**************
|
||
* Mark Members *
|
||
*****************/
|
||
/// Return the incremental mark of the face
|
||
#ifdef __VCGLIB_FACE_M
|
||
inline int & IMark()
|
||
{
|
||
assert( (flags & DELETED) == 0 );
|
||
assert( (flags & NOTREAD) == 0 );
|
||
assert( (flags & NOTWRITE) == 0 );
|
||
return imark;
|
||
}
|
||
|
||
inline const int & IMark() const
|
||
{
|
||
assert( (flags & DELETED) == 0 );
|
||
assert( (flags & NOTREAD) == 0 );
|
||
return imark;
|
||
}
|
||
#endif // Mark
|
||
|
||
/// Initialize the imark system of the face
|
||
inline void InitIMark()
|
||
{
|
||
#ifdef __VCGLIB_FACE_M
|
||
imark = 0;
|
||
#endif
|
||
}
|
||
|
||
/// Return the DOUBLE of the area of the face
|
||
FCTYPE Area() const
|
||
{
|
||
return Norm( (V(1)->P() - V(0)->P()) ^ (V(2)->P() - V(0)->P()) );
|
||
}
|
||
|
||
vectorial_type Barycenter() const
|
||
{
|
||
return (V(0)->P()+V(1)->P()+V(2)->P())/FCTYPE(3.0);
|
||
}
|
||
|
||
FCTYPE Perimeter() const
|
||
{
|
||
return Distance(V(0)->P(),V(1)->P())+
|
||
Distance(V(1)->P(),V(2)->P())+
|
||
Distance(V(2)->P(),V(0)->P());
|
||
}
|
||
|
||
/// Return the quality of the face, the return value is in [0,sqrt(3)/2] = [0 - 0.866.. ]
|
||
FCTYPE QualityFace( ) const
|
||
{
|
||
|
||
return Quality(V(0)->P(), V(1)->P(), V(2)->P());
|
||
/*
|
||
vectorial_type d10 = V(1)->P() - V(0)->P();
|
||
vectorial_type d20 = V(2)->P() - V(0)->P();
|
||
vectorial_type d12 = V(1)->P() - V(2)->P();
|
||
|
||
vectorial_type x = d10^d20;
|
||
|
||
FCTYPE a = Norm( x ); // doppio dell' Area
|
||
FCTYPE b;
|
||
|
||
b = Norm2( d10 );
|
||
FCTYPE t = b;
|
||
t = Norm2( d20 ); if( b<t ) b = t;
|
||
t = Norm2( d12 ); if( b<t ) b = t;
|
||
|
||
assert(b!=0.0);
|
||
|
||
return a/b;*/
|
||
|
||
}
|
||
|
||
// Funzione di supporto
|
||
inline void Nexts( face_base *&f,int &z )
|
||
{
|
||
int t;
|
||
t = z;
|
||
z = (*f).Z(z);
|
||
f = (*f).F(t);
|
||
}
|
||
|
||
/** This function change the orientation of the face. Inverting the index of two vertex
|
||
@param z Index of the edge
|
||
*/
|
||
void Swap ( const int z )
|
||
{
|
||
|
||
int i;
|
||
face_base *tmp, *prec;
|
||
int t, precz;
|
||
|
||
swap ( V((z )%3),V((z+1)%3));
|
||
|
||
if( OBJ_TYPE & (OBJ_TYPE_A|OBJ_TYPE_S ) )
|
||
{
|
||
swap ( F((z+1)%3),F((z+2)%3));
|
||
swap ( Z((z+1)%3),Z((z+2)%3));
|
||
|
||
for(i = 1; i < 3; i++)
|
||
{
|
||
|
||
tmp = this;
|
||
t = (z+i)%3;
|
||
do {
|
||
prec = tmp;
|
||
precz = t;
|
||
Nexts(tmp,t);
|
||
}
|
||
while (tmp != this);
|
||
|
||
(*prec).Z(precz) = (z+i)%3;
|
||
}
|
||
}
|
||
}
|
||
|
||
/*void Swap( const int e )
|
||
{
|
||
swap( V(e), V((e+1)%3) );
|
||
|
||
#ifdef __VCGLIB_FACE_A
|
||
|
||
swap( F((e+1)%3), F((e+2)%3) );
|
||
swap( Z((e+1)%3), Z((e+2)%3) );
|
||
|
||
F((e+1)%3)->Z(Z((e+1)%3)) = (e+1)%3;
|
||
F((e+2)%3)->Z(Z((e+2)%3)) = (e+2)%3;
|
||
#endif
|
||
}*/
|
||
|
||
// Stacca la faccia corrente dalla catena di facce incidenti sul vertice z,
|
||
// NOTA funziona SOLO per la topologia VF!!!
|
||
// usata nelle classi di collapse
|
||
void VFDetach(int z)
|
||
{
|
||
|
||
if(V(z)->Fp()==this )
|
||
{
|
||
int fz = V(z)->Zp();
|
||
V(z)->Fp() = (face_from_vert_type *) F(fz);
|
||
V(z)->Zp() = Z(fz);
|
||
}
|
||
else
|
||
{
|
||
VEdgePosB<FACE_TYPE> x,y;
|
||
|
||
x.f = V(z)->Fp();
|
||
x.z = V(z)->Zp();
|
||
|
||
for(;;)
|
||
{
|
||
y = x;
|
||
x.NextF();
|
||
assert(x.f!=0);
|
||
if(x.f==this)
|
||
{
|
||
y.f->F(y.z) = F(z);
|
||
y.f->Z(y.z) = Z(z);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Sezione dist e ray
|
||
#ifdef __VCGLIB_FACE_E
|
||
vectorial_type edge[3];
|
||
Plane3<scalar_type> plane;
|
||
|
||
void ComputeE()
|
||
{
|
||
// Primo calcolo degli edges
|
||
edge[0] = V(1)->P(); edge[0] -= V(0)->P();
|
||
edge[1] = V(2)->P(); edge[1] -= V(1)->P();
|
||
edge[2] = V(0)->P(); edge[2] -= V(2)->P();
|
||
// Calcolo di plane
|
||
plane.n = edge[0]^edge[1];
|
||
plane.d = plane.n * V(0)->P();
|
||
plane.Normalize();
|
||
// Calcolo migliore proiezione
|
||
scalar_type nx = Abs(plane.n[0]);
|
||
scalar_type ny = Abs(plane.n[1]);
|
||
scalar_type nz = Abs(plane.n[2]);
|
||
scalar_type d;
|
||
if(nx>ny && nx>nz) { flags |= NORMX; d = 1/plane.n[0]; }
|
||
else if(ny>nz) { flags |= NORMY; d = 1/plane.n[1]; }
|
||
else { flags |= NORMZ; d = 1/plane.n[2]; }
|
||
|
||
// Scalatura spigoli
|
||
edge[0] *= d;
|
||
edge[1] *= d;
|
||
edge[2] *= d;
|
||
}
|
||
|
||
/*
|
||
Point face distance
|
||
trova il punto <p> sulla faccia piu' vicino a <q>, con possibilit<69> di
|
||
rejection veloce su se la distanza trovata <20> maggiore di <rejdist>
|
||
|
||
Commenti del 12/11/02
|
||
Funziona solo se la faccia e di quelle di tipo E (con edge e piano per faccia gia' calcolati)
|
||
algoritmo:
|
||
1) si calcola la proiezione <p> di q sul piano della faccia
|
||
2) se la distanza punto piano e' > rejdist ritorna
|
||
3) si lavora sul piano migliore e si cerca di capire se il punto sta dentro il triangolo:
|
||
a) prodotto vettore tra edge triangolo (v[i+1]-v[i]) e (p-v[i])
|
||
b) se il risultato e' negativo (gira in senso orario) allora il punto
|
||
sta fuori da quella parte e si fa la distanza punto segmento.
|
||
c) se il risultato sempre positivo allora sta dentro il triangolo
|
||
4) e si restituisce la distanza punto /piano gia` calcolata
|
||
|
||
Note sulla robustezza:
|
||
il calcolo del prodotto vettore e` la cosa piu` delicata:
|
||
possibili fallimenti quando a^b ~= 0
|
||
1) doveva essere <= 0 e viene positivo (q era fuori o sulla linea dell'edge)
|
||
allora capita che si faccia la distanza punto piano anziche` la distanza punto seg
|
||
2) doveva essere > 0 e viene <=0 (q era dentro il triangolo)
|
||
|
||
*/
|
||
bool Dist( const vectorial_type & q, scalar_type & dist, vectorial_type & p )
|
||
{
|
||
//const scalar_type EPSILON = scalar_type( 0.000001);
|
||
const scalar_type EPSILON = 0.00000001;
|
||
scalar_type b,b0,b1,b2;
|
||
// Calcolo distanza punto piano
|
||
scalar_type d = Distance( plane, q );
|
||
if( d>dist || d<-dist ) // Risultato peggiore: niente di fatto
|
||
return false;
|
||
|
||
// Calcolo del punto sul piano
|
||
// NOTA: aggiunto un '-d' in fondo Paolo C.
|
||
vectorial_type t = plane.n;
|
||
t[0] *= -d;
|
||
t[1] *= -d;
|
||
t[2] *= -d;
|
||
p = q; p += t;
|
||
|
||
#define PP(i) (v[i]->P())
|
||
#define E(i) (edge[i])
|
||
|
||
switch( flags & (NORMX|NORMY|NORMZ) )
|
||
{
|
||
case NORMX:
|
||
b0 = E(1)[1]*(p[2] - PP(1)[2]) - E(1)[2]*(p[1] - PP(1)[1]);
|
||
if(b0<=0)
|
||
{
|
||
b0 = PSDist(q,V(1)->P(),V(2)->P(),p);
|
||
if(dist>b0) { dist = b0; return true; }
|
||
else return false;
|
||
}
|
||
b1 = E(2)[1]*(p[2] - PP(2)[2]) - E(2)[2]*(p[1] - PP(2)[1]);
|
||
if(b1<=0)
|
||
{
|
||
b1 = PSDist(q,V(2)->P(),V(0)->P(),p);
|
||
if(dist>b1) { dist = b1; return true; }
|
||
else return false;
|
||
}
|
||
b2 = E(0)[1]*(p[2] - PP(0)[2]) - E(0)[2]*(p[1] - PP(0)[1]);
|
||
if(b2<=0)
|
||
{
|
||
b2 = PSDist(q,V(0)->P(),V(1)->P(),p);
|
||
if(dist>b2) { dist = b2; return true; }
|
||
else return false;
|
||
}
|
||
// sono tutti e tre > 0 quindi dovrebbe essere dentro;
|
||
// per sicurezza se il piu' piccolo dei tre e' < epsilon (scalato rispetto all'area della faccia
|
||
// per renderlo dimension independent.) allora si usa ancora la distanza punto
|
||
// segmento che e' piu robusta della punto piano, e si fa dalla parte a cui siamo piu'
|
||
// vicini (come prodotto vettore)
|
||
// Nota: si potrebbe rendere un pochino piu' veloce sostituendo Area()
|
||
// con il prodotto vettore dei due edge in 2d lungo il piano migliore.
|
||
if( (b=min(b0,min(b1,b2))) < EPSILON*Area())
|
||
{
|
||
scalar_type bt;
|
||
if(b==b0) bt = PSDist(q,V(1)->P(),V(2)->P(),p);
|
||
else if(b==b1) bt = PSDist(q,V(2)->P(),V(0)->P(),p);
|
||
else if(b==b2) bt = PSDist(q,V(0)->P(),V(1)->P(),p);
|
||
//printf("Warning area:%g %g %g %g thr:%g bt:%g\n",Area(), b0,b1,b2,EPSILON*Area(),bt);
|
||
if(dist>bt) { dist = bt; return true; }
|
||
else return false;
|
||
}
|
||
break;
|
||
|
||
case NORMY:
|
||
b0 = E(1)[2]*(p[0] - PP(1)[0]) - E(1)[0]*(p[2] - PP(1)[2]);
|
||
if(b0<=0)
|
||
{
|
||
b0 = PSDist(q,V(1)->P(),V(2)->P(),p);
|
||
if(dist>b0) { dist = b0; return true; }
|
||
else return false;
|
||
}
|
||
b1 = E(2)[2]*(p[0] - PP(2)[0]) - E(2)[0]*(p[2] - PP(2)[2]);
|
||
if(b1<=0)
|
||
{
|
||
b1 = PSDist(q,V(2)->P(),V(0)->P(),p);
|
||
if(dist>b1) { dist = b1; return true; }
|
||
else return false;
|
||
}
|
||
b2 = E(0)[2]*(p[0] - PP(0)[0]) - E(0)[0]*(p[2] - PP(0)[2]);
|
||
if(b2<=0)
|
||
{
|
||
b2 = PSDist(q,V(0)->P(),V(1)->P(),p);
|
||
if(dist>b2) { dist = b2; return true; }
|
||
else return false;
|
||
}
|
||
if( (b=min(b0,min(b1,b2))) < EPSILON*Area())
|
||
{
|
||
scalar_type bt;
|
||
if(b==b0) bt = PSDist(q,V(1)->P(),V(2)->P(),p);
|
||
else if(b==b1) bt = PSDist(q,V(2)->P(),V(0)->P(),p);
|
||
else if(b==b2) bt = PSDist(q,V(0)->P(),V(1)->P(),p);
|
||
//printf("Warning area:%g %g %g %g thr:%g bt:%g\n",Area(), b0,b1,b2,EPSILON*Area(),bt);
|
||
if(dist>bt) { dist = bt; return true; }
|
||
else return false;
|
||
}
|
||
break;
|
||
|
||
case NORMZ:
|
||
b0 = E(1)[0]*(p[1] - PP(1)[1]) - E(1)[1]*(p[0] - PP(1)[0]);
|
||
if(b0<=0)
|
||
{
|
||
b0 = PSDist(q,V(1)->P(),V(2)->P(),p);
|
||
if(dist>b0) { dist = b0; return true; }
|
||
else return false;
|
||
}
|
||
b1 = E(2)[0]*(p[1] - PP(2)[1]) - E(2)[1]*(p[0] - PP(2)[0]);
|
||
if(b1<=0)
|
||
{
|
||
b1 = PSDist(q,V(2)->P(),V(0)->P(),p);
|
||
if(dist>b1) { dist = b1; return true; }
|
||
else return false;
|
||
}
|
||
b2 = E(0)[0]*(p[1] - PP(0)[1]) - E(0)[1]*(p[0] - PP(0)[0]);
|
||
if(b2<=0)
|
||
{
|
||
b2 = PSDist(q,V(0)->P(),V(1)->P(),p);
|
||
if(dist>b2) { dist = b2; return true; }
|
||
else return false;
|
||
}
|
||
if( (b=min(b0,min(b1,b2))) < EPSILON*Area())
|
||
{
|
||
scalar_type bt;
|
||
if(b==b0) bt = PSDist(q,V(1)->P(),V(2)->P(),p);
|
||
else if(b==b1) bt = PSDist(q,V(2)->P(),V(0)->P(),p);
|
||
else if(b==b2) bt = PSDist(q,V(0)->P(),V(1)->P(),p);
|
||
//printf("Warning area:%g %g %g %g thr:%g bt:%g\n",Area(), b0,b1,b2,EPSILON*Area(),bt);
|
||
|
||
if(dist>bt) { dist = bt; return true; }
|
||
else return false;
|
||
}
|
||
break;
|
||
}
|
||
|
||
#undef E
|
||
#undef PP
|
||
|
||
dist = scalar_type(fabs(d));
|
||
//dist = Distance(p,q);
|
||
return true;
|
||
}
|
||
|
||
|
||
//Intersect ray with triangle. This is an optimized version of the
|
||
//intersection routine from Snyder and Barr's '87 SIGGRAPH paper.
|
||
//Si distingue fra distanza negativa e positiva (N e P)
|
||
//Returns 1 or 0
|
||
static inline bool CheckVal( const scalar_type b ){
|
||
return b<-1e-20 || b>1.0+1e-20 ;
|
||
}
|
||
|
||
bool Intersect( Line3<scalar_type> const & r, scalar_type &d )
|
||
{
|
||
const scalar_type EPSILON = 1e-20;
|
||
|
||
vectorial_type p;
|
||
|
||
scalar_type k = plane.n * r.dire; // Plane intersection.
|
||
if (k< EPSILON && k>-EPSILON)
|
||
return false;
|
||
|
||
d = (plane.d - plane.n * r.orig) / k;
|
||
p = r.orig + r.dire*d;
|
||
|
||
scalar_type b;
|
||
|
||
vectorial_type p0 = v[0]->P();
|
||
vectorial_type p1 = v[1]->P();
|
||
vectorial_type p2 = v[2]->P();
|
||
|
||
switch(flags & (NORMX|NORMY|NORMZ)){
|
||
case NORMX:
|
||
b= edge[1][1]*(p[2]-p1[2]) - edge[1][2]*(p[1]-p1[1]); if(CheckVal(b)) return false;
|
||
b= edge[2][1]*(p[2]-p2[2]) - edge[2][2]*(p[1]-p2[1]); if(CheckVal(b)) return false;
|
||
b= edge[0][1]*(p[2]-p0[2]) - edge[0][2]*(p[1]-p0[1]); if(CheckVal(b)) return false;
|
||
break;
|
||
case NORMY:
|
||
b= edge[1][2]*(p[0]-p1[0]) - edge[1][0]*(p[2]-p1[2]); if(CheckVal(b)) return false;
|
||
b= edge[2][2]*(p[0]-p2[0]) - edge[2][0]*(p[2]-p2[2]); if(CheckVal(b)) return false;
|
||
b= edge[0][2]*(p[0]-p0[0]) - edge[0][0]*(p[2]-p0[2]); if(CheckVal(b)) return false;
|
||
break;
|
||
case NORMZ:
|
||
b= edge[1][0]*(p[1]-p1[1]) - edge[1][1]*(p[0]-p1[0]); if(CheckVal(b)) return false;
|
||
b= edge[2][0]*(p[1]-p2[1]) - edge[2][1]*(p[0]-p2[0]); if(CheckVal(b)) return false;
|
||
b= edge[0][0]*(p[1]-p0[1]) - edge[0][1]*(p[0]-p0[0]); if(CheckVal(b)) return false;
|
||
break;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
#endif
|
||
|
||
// Intersect ray with triangle.
|
||
// returns barycientric coordinate and dist
|
||
bool Intersect( Line3<scalar_type> const & ray, scalar_type & dist, scalar_type &a, scalar_type &b) {
|
||
//static double a,b;
|
||
return Intersection( ray, v[0]->P(), v[1]->P(), v[2]->P(), a,b, dist );
|
||
};
|
||
|
||
/// return the index [0..2] of a vertex in a face
|
||
inline int VertexIndex( const FVTYPE * w ) const
|
||
{
|
||
if( v[0]==w ) return 0;
|
||
else if( v[1]==w ) return 1;
|
||
else if( v[2]==w ) return 2;
|
||
else return -1;
|
||
}
|
||
|
||
/// Return the texture distorsion
|
||
scalar_type texture_distorsion( int nt=0 ) const
|
||
{
|
||
#ifndef __VCGLIB_FACE_WT
|
||
assert(0);
|
||
#endif
|
||
scalar_type e = 0;
|
||
for(int nz=0;nz<3;++nz)
|
||
{
|
||
scalar_type l0 = Distance( V1(nz)->P(),V(nz)->P() );
|
||
scalar_type l1 = Distance( WT((nz+1)%3).t(nt), WT(nz).t(nt) );
|
||
scalar_type dl = l1-l0;
|
||
e += dl*dl;
|
||
}
|
||
e = (e/3)/ Area();
|
||
return e;
|
||
}
|
||
|
||
/// Return the texture distorsion
|
||
scalar_type hoppe_distorsion( int nt=0 ) const
|
||
{
|
||
#ifndef __VCGLIB_FACE_WT
|
||
assert(0);
|
||
#endif
|
||
scalar_type A = Area();
|
||
|
||
scalar_type s1 = WT(0).u(nt);
|
||
scalar_type t1 = WT(0).v(nt);
|
||
scalar_type s2 = WT(1).u(nt);
|
||
scalar_type t2 = WT(1).v(nt);
|
||
scalar_type s3 = WT(2).u(nt);
|
||
scalar_type t3 = WT(2).v(nt);
|
||
|
||
vectorial_type Ss = (V(0)->P()*(t2-t3)+V(1)->P()*(t3-t1)+V(2)->P()*(t1-t2))/(2*A);
|
||
vectorial_type St = (V(0)->P()*(s3-s2)+V(1)->P()*(s1-s3)+V(2)->P()*(s2-s1))/(2*A);
|
||
|
||
scalar_type a = Ss*Ss;
|
||
scalar_type b = Ss*St;
|
||
scalar_type c = St*St;
|
||
|
||
return sqrt((a+c)/2+sqrt((a-c)*(a-c)+4*b*b));
|
||
}
|
||
|
||
}; //end Class
|
||
|
||
|
||
|
||
|
||
} // end namespace
|
||
|
||
|
||
#endif
|
||
|