c91c2a9720
- aggiunte funzioni per calcolo elevazione di Poligono in Box e in TriMesh chiusa.
493 lines
16 KiB
C++
493 lines
16 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2015-2020
|
|
//----------------------------------------------------------------------------
|
|
// File : Polygon3d.cpp Data : 03.04.20 Versione : 2.2d1
|
|
// Contenuto : Implementazione della classe Polygon3d.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 30.08.15 DS Creazione modulo.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//--------------------------- Include ----------------------------------------
|
|
#include "stdafx.h"
|
|
#include "PolygonPlane.h"
|
|
#include "CurveComposite.h"
|
|
#include "SurfFlatRegion.h"
|
|
#include "GeoConst.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)
|
|
{
|
|
// pulisco tutto
|
|
Clear() ;
|
|
// 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)
|
|
{
|
|
// pulisco tutto
|
|
Clear() ;
|
|
// 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)
|
|
{
|
|
// pulisco tutto
|
|
Clear() ;
|
|
// 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, bool bOnEq, bool bOnCt, double dToler)
|
|
{
|
|
// pulisco tutto
|
|
Clear() ;
|
|
// il piano e il box devono essere validi
|
|
if ( plPlane.GetVersN().IsSmall() || AreSamePointApprox( ptMin, ptMax))
|
|
return false ;
|
|
// assegno il piano
|
|
Plane3d plTemp = plPlane ;
|
|
// se piano molto vicino ad uno dei vertici del box, lo faccio passare esattamente per il vertice
|
|
if ( dToler > EPS_SMALL) {
|
|
PNTVECTOR vBoxVert = { Point3d( ptMin.x, ptMin.y, ptMin.z), Point3d( ptMin.x, ptMin.y, ptMax.z),
|
|
Point3d( ptMax.x, ptMin.y, ptMin.z), Point3d( ptMax.x, ptMin.y, ptMax.z),
|
|
Point3d( ptMin.x, ptMax.y, ptMin.z), Point3d( ptMin.x, ptMax.y, ptMax.z),
|
|
Point3d( ptMax.x, ptMax.y, ptMin.z), Point3d( ptMax.x, ptMax.y, ptMax.z)} ;
|
|
for ( const auto& ptP : vBoxVert) {
|
|
if ( abs( DistPointPlane( ptP, plTemp)) < dToler) {
|
|
Point3d ptNear = ProjectPointOnPlane( ptP, plTemp) ;
|
|
Vector3d vtDelta = ptP - ptNear ;
|
|
plTemp.Offset( vtDelta * plTemp.GetVersN()) ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
// centro del box proiettato nel piano
|
|
Point3d ptCen = Media( ptMin, ptMax, 0.5) ;
|
|
ptCen -= (( ptCen - ORIG) * plTemp.GetVersN() - plTemp.GetDist()) * plTemp.GetVersN() ;
|
|
// raggio del box
|
|
double dDiam = Dist( ptMin, ptMax) ;
|
|
// poligono nel suo piano
|
|
FromRectangle( dDiam, dDiam) ;
|
|
// riferimento del piano
|
|
Frame3d frRef ;
|
|
frRef.Set( ptCen, plTemp.GetVersN(), FromUprightOrtho( plTemp.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, bOnEq, bOnCt) ;
|
|
plFace.Set( -ptMin.z, -Z_AX) ; // faccia 2 (Norm = Z-)
|
|
Trim( plFace, true, bOnEq, bOnCt) ;
|
|
plFace.Set( ptMax.y, Y_AX) ; // faccia 3 (Norm = Y+)
|
|
Trim( plFace, true, bOnEq, bOnCt) ;
|
|
plFace.Set( ptMax.z, Z_AX) ; // faccia 4 (Norm = Z+)
|
|
Trim( plFace, true, bOnEq, bOnCt) ;
|
|
plFace.Set( -ptMin.x, -X_AX) ; // faccia 5 (Norm = X-)
|
|
Trim( plFace, true, bOnEq, bOnCt) ;
|
|
plFace.Set( ptMax.x, X_AX) ; // faccia 6 (Norm = X+)
|
|
Trim( plFace, true, bOnEq, bOnCt) ;
|
|
// elimino eventuali vertici coincidenti
|
|
for ( int i = 1 ; i < int( m_vVert.size()) ;) {
|
|
if ( SqDist( m_vVert[i], m_vVert[i-1]) < SQ_EPS_SMALL) {
|
|
m_vVert[i-1] = Media( m_vVert[i-1], m_vVert[i]) ;
|
|
m_vVert.erase( m_vVert.begin() + i) ;
|
|
}
|
|
else
|
|
++ i ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Polygon3d::FromPlaneTrimmedWithBox( const Point3d& ptOn, const Vector3d& vtN,
|
|
const Point3d& ptMin, const Point3d& ptMax, bool bOnEq, bool bOnCt, double dToler)
|
|
{
|
|
Plane3d plPlane ;
|
|
plPlane.Set( ptOn, vtN) ;
|
|
return FromPlaneTrimmedWithBox( plPlane, ptMin, ptMax, bOnEq, bOnCt) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Polygon3d::Trim( const Plane3d& plPlane, bool bInVsOut, bool bOnEq, bool bOnCt)
|
|
{
|
|
// 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 = DistPointPlane( ptP, plPlane) ;
|
|
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 opposte a entrambi i desiderati, lo annullo
|
|
if ( ( bEquivNormal && ! bOnEq) || ( ! bEquivNormal && ! bOnCt))
|
|
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, bool bOnCt)
|
|
{
|
|
if ( GetSideCount() == 0 || ! plyOther.IsValid())
|
|
return true ;
|
|
return Trim( plyOther.m_Plane, bInVsOut, bOnEq, bOnCt) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Polygon3d::Add( const Polygon3d& plyOther)
|
|
{
|
|
// se l'altro vuoto, non devo fare alcunché
|
|
if ( plyOther.GetSideCount() == 0)
|
|
return true ;
|
|
// se questo vuoto, devo copiare l'altro
|
|
if ( GetSideCount() == 0) {
|
|
*this = plyOther ;
|
|
return true ;
|
|
}
|
|
// verifico siano complanari
|
|
if ( ! AreSameVectorApprox( GetVersN(), plyOther.GetVersN()) &&
|
|
abs( GetPlaneDist() - plyOther.GetPlaneDist()) > EPS_SMALL)
|
|
return false ;
|
|
// creo la regione del poligono
|
|
CurveComposite crvThis ;
|
|
crvThis.FromPolyLine( GetPolyLine()) ;
|
|
SurfFlatRegion frThis ;
|
|
if ( ! frThis.AddExtLoop( crvThis))
|
|
return false ;
|
|
// creo la regione dell'altro poligono
|
|
CurveComposite crvOther ;
|
|
crvOther.FromPolyLine( plyOther.GetPolyLine()) ;
|
|
SurfFlatRegion frOther ;
|
|
if ( ! frOther.AddExtLoop( crvOther))
|
|
return false ;
|
|
// unisco le due regioni e verifico che il risultato sia un solo pezzo
|
|
if ( ! frThis.Add( frOther) && frThis.GetChunkCount() != 1)
|
|
return false ;
|
|
// recupero il contorno della regione
|
|
PolyLine PL ;
|
|
if ( ! frThis.ApproxLoopWithLines( 0, 0, EPS_SMALL, ANG_TOL_MIN_DEG, ICurve::APL_STD, PL))
|
|
return false ;
|
|
// lo impongo come nuovo poligono
|
|
return FromPolyLine( PL) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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 ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Polygon3d::GetLocalBBox( BBox3d& b3Loc) const
|
|
{
|
|
// assegno il box in locale, scorrendo tutti i punti del contorno
|
|
b3Loc.Reset() ;
|
|
for ( const auto& ptP : m_vVert)
|
|
b3Loc.Add( ptP) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
Polygon3d::Invert( void)
|
|
{
|
|
reverse( m_vVert.begin(), m_vVert.end()) ;
|
|
m_Plane.Invert() ;
|
|
}
|