Files
EgtGeomKernel/Polygon3d.cpp
T
Dario Sassi fba63ea82e EgtGeomKernel :
- aggiunte funzioni per verifica collisione tra Box, Cilindro e Sfera con Superfici triMesh chiuse
- aggiunta costruzione di Polygon3d da triangolo.
2020-01-10 09:32:59 +00:00

411 lines
13 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2015-2017
//----------------------------------------------------------------------------
// File : Polygon3d.cpp Data : 15.10.17 Versione : 1.8j3
// Contenuto : Implementazione della classe Polygon3d.
//
//
//
// Modifiche : 30.08.15 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "PolygonPlane.h"
#include "/EgtDev/Include/EgkPolygon3d.h"
using namespace std ;
//----------------------------------------------------------------------------
bool
Polygon3d::Clear( void)
{
m_Plane.Reset() ;
m_vVert.clear() ;
return true ;
}
//----------------------------------------------------------------------------
bool
Polygon3d::ClearSides( void)
{
m_vVert.clear() ;
return true ;
}
//----------------------------------------------------------------------------
bool
Polygon3d::FromRectangle( double dDimX, double dDimY)
{
// verifico i dati
if ( dDimX < EPS_SMALL || dDimY < EPS_SMALL)
return false ;
// assegno il piano
m_Plane.Set( 0, Z_AX) ;
// assegno i vertici del poligono
m_vVert.reserve( 4) ;
m_vVert.emplace_back( + 0.5 * dDimX, + 0.5 * dDimY, 0) ;
m_vVert.emplace_back( - 0.5 * dDimX, + 0.5 * dDimY, 0) ;
m_vVert.emplace_back( - 0.5 * dDimX, - 0.5 * dDimY, 0) ;
m_vVert.emplace_back( + 0.5 * dDimX, - 0.5 * dDimY, 0) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Polygon3d::FromTriangle( const Triangle3d& trTria)
{
// annullo il piano del poligono
m_Plane.Reset() ;
// verifico che il triangolo sia valido
if ( ! trTria.IsValid())
return false ;
// assegno il piano
m_Plane.Set( trTria.GetP( 0), trTria.GetN()) ;
// assegno i punti
m_vVert.emplace_back( trTria.GetP( 0)) ;
m_vVert.emplace_back( trTria.GetP( 1)) ;
m_vVert.emplace_back( trTria.GetP( 2)) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Polygon3d::FromPolyLine( const PolyLine& PL)
{
// annullo il piano del poligono
m_Plane.Reset() ;
// verifico sia chiusa e piana
Plane3d plPlane ;
double dArea ;
if ( ! PL.IsClosedAndFlat( plPlane, dArea))
return false ;
// assegno il piano
m_Plane = plPlane ;
// assegno i punti
Point3d ptP ;
bool bPoint = PL.GetFirstPoint( ptP, true) ;
// inserisco i punti
while ( bPoint) {
m_vVert.emplace_back( ptP) ;
bPoint = PL.GetNextPoint( ptP, true) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Polygon3d::FromPlaneTrimmedWithBox( const Plane3d& plPlane, const Point3d& ptMin, const Point3d& ptMax)
{
// il piano e il box devono essere validi
if ( plPlane.GetVersN().IsSmall() || AreSamePointApprox( ptMin, ptMax))
return false ;
// assegno il piano
m_Plane = plPlane ;
// centro del box proiettato nel piano
Point3d ptCen = Media( ptMin, ptMax, 0.5) ;
ptCen -= (( ptCen - ORIG) * plPlane.GetVersN() - plPlane.GetDist()) * plPlane.GetVersN() ;
// raggio del box
double dDiam = Dist( ptMin, ptMax) ;
// poligono nel suo piano
FromRectangle( dDiam, dDiam) ;
// riferimento del piano
Frame3d frRef ;
frRef.Set( ptCen, plPlane.GetVersN(), FromUprightOrtho( plPlane.GetVersN())) ;
ToGlob( frRef) ;
// lo trimmo con le facce del box
Plane3d plFace ;
plFace.Set( -ptMin.y, -Y_AX) ; // faccia 1 (Norm = Y-)
Trim( plFace, true, true) ;
plFace.Set( -ptMin.z, -Z_AX) ; // faccia 2 (Norm = Z-)
Trim( plFace, true, true) ;
plFace.Set( ptMax.y, Y_AX) ; // faccia 3 (Norm = Y+)
Trim( plFace, true, true) ;
plFace.Set( ptMax.z, Z_AX) ; // faccia 4 (Norm = Z+)
Trim( plFace, true, true) ;
plFace.Set( -ptMin.x, -X_AX) ; // faccia 5 (Norm = X-)
Trim( plFace, true, true) ;
plFace.Set( ptMax.x, X_AX) ; // faccia 6 (Norm = X+)
Trim( plFace, true, true) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Polygon3d::FromPlaneTrimmedWithBox( const Point3d& ptOn, const Vector3d& vtN, const Point3d& ptMin, const Point3d& ptMax)
{
Plane3d plPlane ;
if ( plPlane.Set( ptOn, vtN))
return false ;
return FromPlaneTrimmedWithBox( plPlane, ptMin, ptMax) ;
}
//----------------------------------------------------------------------------
bool
Polygon3d::Trim( const Plane3d& plPlane, bool bInVsOut, bool bOnEq)
{
// calcolo le distanze dei punti del poligono dal piano
int nNbrMinus = 0 ;
int nNbrOn = 0 ;
int nNbrPlus = 0 ;
DBLVECTOR vDist ;
vDist.reserve( m_vVert.capacity()) ;
for ( auto& ptP : m_vVert) {
double dDist = ( ptP - ORIG) * plPlane.GetVersN() - plPlane.GetDist() ;
if ( abs( dDist) < EPS_SMALL)
++ nNbrOn ;
else if ( dDist < 0)
++ nNbrMinus ;
else
++ nNbrPlus ;
vDist.push_back( dDist) ;
}
// se il poligono giace nel piano
if ( nNbrMinus == 0 && nNbrPlus == 0) {
// determino se normali equiverse
bool bEquivNormal = ( m_Plane.GetVersN() * plPlane.GetVersN() > 0) ;
// se relazione tra normali opposta al desiderato, lo annullo
if ( bOnEq != bEquivNormal)
m_vVert.clear() ;
return true ;
}
// se altrimenti è tutto dalla parte positiva
else if ( nNbrMinus == 0) {
// se richiesto interno, lo annullo
if ( bInVsOut)
m_vVert.clear() ;
return true ;
}
// se altrimenti è tutto dalla parte negativa
else if ( nNbrPlus == 0) {
// se richiesto esterno, lo annullo
if ( ! bInVsOut)
m_vVert.clear() ;
return true ;
}
// determino le intersezioni dei lati con il piano
for ( size_t i = 0 ; i < m_vVert.size() ; ++ i) {
// indice del punto finale del lato
size_t j = ( ( i + 1 < m_vVert.size()) ? i + 1 : 0) ;
// se il lato attraversa il piano, inserisco il punto di intersezione nel poligono
if ( ( vDist[i] > EPS_SMALL && vDist[j] < - EPS_SMALL) ||
( vDist[i] < - EPS_SMALL && vDist[j] > EPS_SMALL)) {
double dCoeff = abs( vDist[i]) / ( abs( vDist[i]) + abs( vDist[j])) ;
Point3d ptInt = Media( m_vVert[i], m_vVert[j], dCoeff) ;
m_vVert.insert( m_vVert.begin() + i + 1, ptInt) ;
vDist.insert( vDist.begin() + i + 1, 0.0) ;
++ i ;
}
}
// elimino i punti che non rispettano la posizione rispetto al piano
for ( size_t i = 0 ; i < m_vVert.size() ; ++ i) {
if ( ( bInVsOut && vDist[i] > EPS_SMALL) ||
( ! bInVsOut && vDist[i] < - EPS_SMALL)) {
m_vVert.erase( m_vVert.begin() + i) ;
vDist.erase( vDist.begin() + i) ;
-- i ;
}
}
// se i punti rimasti giacciono tutti sul piano (quindi su una linea), annullo il poligono
bool bIsLine = true ;
for ( auto& dDist : vDist) {
if ( abs( dDist) > EPS_SMALL)
bIsLine = false ;
}
if ( bIsLine)
m_vVert.clear() ;
return true ;
}
//----------------------------------------------------------------------------
bool
Polygon3d::Trim( const Polygon3d& plyOther, bool bInVsOut, bool bOnEq)
{
if ( GetSideCount() == 0 || ! plyOther.IsValid())
return true ;
return Trim( plyOther.m_Plane, bInVsOut, bOnEq) ;
}
//----------------------------------------------------------------------------
PolyLine
Polygon3d::GetPolyLine( void) const
{
PolyLine PL ;
// se il piano non è definito, errore
if ( m_Plane.GetVersN().IsSmall())
return PL ;
// converto il poligono in PolyLine
for ( size_t i = 0 ; i < m_vVert.size() ; ++ i)
PL.AddUPoint( int( i), m_vVert[i]) ;
PL.Close() ;
return PL ;
}
//----------------------------------------------------------------------------
Point3d
Polygon3d::GetCentroid( void) const
{
PolygonPlane PolyPlane ;
for ( const auto& ptP : m_vVert)
PolyPlane.AddPoint( ptP) ;
Point3d ptCen ;
PolyPlane.GetCentroid( ptCen) ;
return ptCen ;
}
//----------------------------------------------------------------------------
double
Polygon3d::GetPerimeter( void) const
{
double dLen = 0 ;
for ( size_t i = 0 ; i < m_vVert.size() ; ++ i) {
size_t j = ( i + 1 < m_vVert.size() ? i + 1 : 0) ;
dLen += Dist( m_vVert[i], m_vVert[j]) ;
}
return dLen ;
}
//----------------------------------------------------------------------------
double
Polygon3d::GetArea( void) const
{
double dArea = 0 ;
PolygonPlane PolyPlane ;
for ( const auto& ptP : m_vVert)
PolyPlane.AddPoint( ptP) ;
return ( PolyPlane.GetArea( dArea) ? dArea : 0) ;
}
//----------------------------------------------------------------------------
void
Polygon3d::Translate( const Vector3d& vtMove)
{
// traslo il piano
m_Plane.Translate( vtMove) ;
// traslo i punti
for ( auto& ptP : m_vVert)
ptP.Translate( vtMove) ;
}
//----------------------------------------------------------------------------
bool
Polygon3d::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, double dSinAng)
{
// ruoto il piano
if ( ! m_Plane.Rotate( ptAx, vtAx, dCosAng, dSinAng))
return false ;
// ruoto i punti
for ( auto& ptP : m_vVert)
ptP.Rotate( ptAx, vtAx, dCosAng, dSinAng) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Polygon3d::Scale( const Frame3d& frRef, double dCoeffX, double dCoeffY, double dCoeffZ)
{
// verifico validità della scalatura
if ( abs( dCoeffX) < EPS_ZERO && abs( dCoeffY) < EPS_ZERO && abs( dCoeffZ) < EPS_ZERO)
return false ;
// scalo il piano
if ( ! m_Plane.Scale( frRef, dCoeffX, dCoeffY, dCoeffZ))
return false ;
// scalo i punti
for ( auto& ptP : m_vVert)
ptP.Scale( frRef, dCoeffX, dCoeffY, dCoeffZ) ;
// determino se contiene anche un mirror (numero dispari di coefficienti negativi)
bool bMirror = ( dCoeffX < 0) ;
bMirror = ( bMirror ? ( dCoeffY > 0) : ( dCoeffY < 0)) ;
bMirror = ( bMirror ? ( dCoeffZ > 0) : ( dCoeffZ < 0)) ;
if ( bMirror)
reverse( m_vVert.begin(), m_vVert.end()) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Polygon3d::Mirror( const Point3d& ptOn, const Vector3d& vtNorm)
{
// specchio il piano
if ( ! m_Plane.Mirror( ptOn, vtNorm))
return false ;
// specchio i punti e ne inverto l'ordine
for ( auto& ptP : m_vVert)
ptP.Mirror( ptOn, vtNorm) ;
reverse( m_vVert.begin(), m_vVert.end()) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Polygon3d::Shear( const Point3d& ptOn, const Vector3d& vtNorm, const Vector3d& vtDir, double dCoeff)
{
// stiro il piano
if ( ! m_Plane.Shear( ptOn, vtNorm, vtDir, dCoeff))
return false ;
// stiro i punti
for ( auto& ptP : m_vVert)
ptP.Shear( ptOn, vtNorm, vtDir, dCoeff) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Polygon3d::ToGlob( const Frame3d& frRef)
{
// trasformo il piano
if ( ! m_Plane.ToGlob( frRef))
return false ;
// trasformo i punti
for ( auto& ptP : m_vVert)
ptP.ToGlob( frRef) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Polygon3d::ToLoc( const Frame3d& frRef)
{
// trasformo il piano
if ( ! m_Plane.ToLoc( frRef))
return false ;
// trasformo i punti
for ( auto& ptP : m_vVert)
ptP.ToLoc( frRef) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Polygon3d::LocToLoc( const Frame3d& frOri, const Frame3d& frDest)
{
// se i due riferimenti coincidono, non devo fare alcunché
if ( AreSameFrame( frOri, frDest))
return true ;
// trasformo il piano
if ( ! m_Plane.LocToLoc( frOri, frDest))
return false ;
// trasformo i punti
for ( auto& ptP : m_vVert)
ptP.LocToLoc( frOri, frDest) ;
return true ;
}
//----------------------------------------------------------------------------
void
Polygon3d::Invert( void)
{
reverse( m_vVert.begin(), m_vVert.end()) ;
m_Plane.Invert() ;
}