07072b370f
- aggiornamenti vari.
208 lines
7.9 KiB
C++
208 lines
7.9 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2014-2015
|
|
//----------------------------------------------------------------------------
|
|
// File : EGkTria3d.h Data : 07.02.15 Versione : 1.6b2
|
|
// Contenuto : Dichiarazione classe triangolo Triangle3d.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 30.03.14 DS Creazione modulo.
|
|
// 07.02.15 DS Agg. GetArea e GetAspectRatio.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#pragma once
|
|
|
|
#include "/EgtDev/Include/EGkPoint3d.h"
|
|
#include <algorithm>
|
|
|
|
//-----------------------------------------------------------------------------
|
|
class Triangle3d
|
|
{
|
|
public :
|
|
Triangle3d( void)
|
|
{}
|
|
void Set( const Point3d& ptP0, const Point3d& ptP1, const Point3d& ptP2)
|
|
{ ptP[0] = ptP0 ; ptP[1] = ptP1 ; ptP[2] = ptP2 ; vtN.Set( 0, 0, 0) ; }
|
|
void Set( const Point3d& ptP0, const Point3d& ptP1, const Point3d& ptP2, const Vector3d& vtV)
|
|
{ ptP[0] = ptP0 ; ptP[1] = ptP1 ; ptP[2] = ptP2 ; vtN = vtV ; }
|
|
bool SetP( int nId, const Point3d& ptV)
|
|
{ if ( nId < 0 || nId >= 3)
|
|
return false ;
|
|
ptP[nId] = ptV ;
|
|
return true ;
|
|
}
|
|
bool Validate( void)
|
|
{ if ( AreSamePointApprox( ptP[0], ptP[1]) || AreSamePointApprox( ptP[0], ptP[2]))
|
|
return false ;
|
|
Vector3d vtV = ( ptP[1] - ptP[0]) ^ ( ptP[2] - ptP[0]) ;
|
|
vtV.Normalize() ;
|
|
if ( ! vtN.IsZero())
|
|
return AreSameVectorApprox( vtV, vtN) ;
|
|
vtN = vtV ;
|
|
return true ;
|
|
}
|
|
bool ToGlob( const Frame3d& frRef)
|
|
{ return ( ptP[0].ToGlob( frRef) && ptP[1].ToGlob( frRef) && ptP[2].ToGlob( frRef)) ; }
|
|
bool ToLoc( const Frame3d& frRef)
|
|
{ return ( ptP[0].ToLoc( frRef) && ptP[1].ToLoc( frRef) && ptP[2].ToLoc( frRef)) ; }
|
|
bool LocToLoc( const Frame3d& frOri, const Frame3d& frDest)
|
|
{ return ( ptP[0].LocToLoc( frOri, frDest) &&
|
|
ptP[1].LocToLoc( frOri, frDest) &&
|
|
ptP[2].LocToLoc( frOri, frDest)) ; }
|
|
const Point3d& GetP( int nId) const
|
|
{ if ( nId >= 0 && nId < 3)
|
|
return ptP[nId] ;
|
|
else if ( nId < 0)
|
|
return ptP[0] ;
|
|
else
|
|
return ptP[2] ;
|
|
}
|
|
const Vector3d& GetN( void) const
|
|
{ return vtN ; }
|
|
Point3d GetCentroid( void) const
|
|
{ return ( ptP[0] + ptP[1] + ptP[2]) / 3 ; }
|
|
double GetArea( void) const
|
|
{ return (( ptP[1] - ptP[0]) ^ ( ptP[2] - ptP[0])).Len() / 2 ; }
|
|
double GetAspectRatio( void) const
|
|
{ double dSqDistA = SqDist( ptP[0], ptP[1]) ;
|
|
double dSqDistB = SqDist( ptP[1], ptP[2]) ;
|
|
double dSqDistC = SqDist( ptP[2], ptP[0]) ;
|
|
double dTwoArea = (( ptP[1] - ptP[0]) ^ ( ptP[2] - ptP[0])).Len() ;
|
|
if ( dTwoArea < EPS_SMALL * EPS_SMALL)
|
|
return INFINITO ;
|
|
else
|
|
return ( (std::max)( dSqDistA, (std::max)( dSqDistB, dSqDistC)) / dTwoArea) ;
|
|
}
|
|
|
|
private :
|
|
Point3d ptP[3] ;
|
|
Vector3d vtN ;
|
|
} ;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Flags indicanti se i lati sono parte del contorno di un poligono di più triangoli
|
|
class TriFlags3d
|
|
{
|
|
public :
|
|
bool bFlag[3] ;
|
|
} ;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Normali sui vertici, ottenute mediando opportunamente coi triangoli vicini
|
|
class TriNormals3d
|
|
{
|
|
public :
|
|
Vector3d vtN[3] ;
|
|
} ;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
enum PlaneType { PL_NULL = 0,
|
|
PL_XY = 1,
|
|
PL_YZ = 2,
|
|
PL_ZX = 3} ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Piano canonico di miglior proiezione (perpendicolare alla componente maggiore della normale)
|
|
inline bool
|
|
CalcProjPlane( const Vector3d& vtN, int& nPlane, bool& bCCW)
|
|
{
|
|
// verifico che la normale non sia nulla
|
|
if ( vtN.IsZero())
|
|
return false ;
|
|
// proiezione sul piano XY (Nz con valore maggiore)
|
|
if ( fabs( vtN.z) > fabs( vtN.x) &&
|
|
fabs( vtN.z) > fabs( vtN.y)) {
|
|
nPlane = PL_XY ;
|
|
bCCW = ( vtN.z > 0) ;
|
|
}
|
|
// proiezione sul piano YZ (Nx con valore maggiore)
|
|
else if ( fabs( vtN.x) > fabs( vtN.y)) {
|
|
nPlane = PL_YZ ;
|
|
bCCW = ( vtN.x > 0) ;
|
|
}
|
|
// proiezione sul piano ZX (Ny con valore maggiore)
|
|
else {
|
|
nPlane = PL_ZX ;
|
|
bCCW = ( vtN.y > 0) ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Prodotto vettoriale nel piano di proiezione ( positivo se i 3 punti in ordine CCW)
|
|
inline double
|
|
TwoAreaInPlane( int nPlane, const Point3d& ptA, const Point3d& ptB, const Point3d& ptC)
|
|
{
|
|
switch ( nPlane) {
|
|
default : // PL_XY
|
|
return ( ptB.x - ptA.x) * ( ptC.y - ptB.y) - ( ptB.y - ptA.y) * ( ptC.x - ptB.x) ;
|
|
case PL_YZ :
|
|
return ( ptB.y - ptA.y) * ( ptC.z - ptB.z) - ( ptB.z - ptA.z) * ( ptC.y - ptB.y) ;
|
|
case PL_ZX :
|
|
return ( ptB.z - ptA.z) * ( ptC.x - ptB.x) - ( ptB.x - ptA.x) * ( ptC.z - ptB.z) ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Prodotto scalare nel piano di proiezione
|
|
inline double
|
|
ProScaInPlane( int nPlane, const Point3d& ptP, const Point3d& ptA, const Point3d& ptB)
|
|
{
|
|
switch ( nPlane) {
|
|
default : // PL_XY
|
|
return ( ptP.x - ptA.x) * ( ptB.x - ptA.x) + ( ptP.y - ptA.y) * ( ptB.y - ptA.y) ;
|
|
case PL_YZ :
|
|
return ( ptP.y - ptA.y) * ( ptB.y - ptA.y) + ( ptP.z - ptA.z) * ( ptB.z - ptA.z) ;
|
|
case PL_ZX :
|
|
return ( ptP.z - ptA.z) * ( ptB.z - ptA.z) + ( ptP.x - ptA.x) * ( ptB.x - ptA.x) ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Coordinate baricentriche di un punto giacente nel piano del triangolo
|
|
inline bool
|
|
BarycentricCoord( const Point3d& ptP, const Triangle3d& Tria,
|
|
double& dU, double& dV, double& dW)
|
|
{
|
|
// calcolo del piano ottimale di proiezione
|
|
int nPlane ;
|
|
bool bCCW ;
|
|
if ( ! CalcProjPlane( Tria.GetN(), nPlane, bCCW))
|
|
return false ;
|
|
// verifico che l'area (doppia) non sia nulla
|
|
double d2Area = TwoAreaInPlane( nPlane, Tria.GetP( 0), Tria.GetP( 1), Tria.GetP( 2)) ;
|
|
if ( fabs( d2Area) < EPS_SMALL * EPS_SMALL)
|
|
return false ;
|
|
// calcolo delle coordinate baricentriche
|
|
double dDenom = 1 / d2Area ;
|
|
dU = TwoAreaInPlane( nPlane, ptP, Tria.GetP( 1), Tria.GetP( 2)) * dDenom ;
|
|
dV = TwoAreaInPlane( nPlane, Tria.GetP( 0), ptP, Tria.GetP( 2)) * dDenom ;
|
|
dW = TwoAreaInPlane( nPlane, Tria.GetP( 0), Tria.GetP( 1), ptP) * dDenom ;
|
|
// devono dare somma unitaria
|
|
double dSumm = dU + dV + dW ;
|
|
if ( fabs( dSumm) < EPS_ZERO)
|
|
return false ;
|
|
if ( fabs( dSumm - 1) > EPS_ZERO) {
|
|
double dDenom = 1 / dSumm ;
|
|
dU *= dDenom ;
|
|
dV *= dDenom ;
|
|
dW *= dDenom ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Normale in un punto del triangolo, come media baricentrica delle normali nei vertici
|
|
inline bool
|
|
CalcNormal( const Point3d& ptP, const Triangle3d& Tria, const TriNormals3d& Tnorms, Vector3d& vtNorm)
|
|
{
|
|
// calcolo le coordinate baricentriche del punto
|
|
double dU, dV, dW ;
|
|
if ( ! BarycentricCoord( ptP, Tria, dU, dV, dW))
|
|
return false ;
|
|
// calcolo la media
|
|
vtNorm = dU * Tnorms.vtN[0] + dV * Tnorms.vtN[1] + dW * Tnorms.vtN[2] ;
|
|
// la normalizzo
|
|
return vtNorm.Normalize() ;
|
|
} |