EgtGeomKernel 1.6b3 :

- aggiunta gestione buchi alle triangolazione di poligoni
- creazione suerfici trimesh da regioni con buchi.
This commit is contained in:
Dario Sassi
2015-02-11 11:38:50 +00:00
parent 48df8ea18c
commit 07405f7de6
25 changed files with 1056 additions and 166 deletions
+4 -4
View File
@@ -266,7 +266,7 @@ CalcCircleCenTgCircle( const Point3d& ptC, const Point3d& ptCen, double dRad, BI
if ( dRad < EPS_SMALL) {
// se la distanza tra i punti è significativa, c'è una soluzione
if ( dDist > EPS_SMALL) {
vCenPtg.push_back( make_pair( ptC, ptCen)) ;
vCenPtg.emplace_back( ptC, ptCen) ;
return 1 ;
}
// altrimenti, nessuna soluzione
@@ -279,13 +279,13 @@ CalcCircleCenTgCircle( const Point3d& ptC, const Point3d& ptCen, double dRad, BI
return 0 ;
// se è minore del raggio, c'è una sola soluzione
else if ( dDist < dRad) {
vCenPtg.push_back( make_pair( ptC, ptCen - vtDir * dRad)) ;
vCenPtg.emplace_back( ptC, ptCen - vtDir * dRad) ;
return 1 ;
}
// altrimenti ci sono due soluzioni
else {
vCenPtg.push_back( make_pair( ptC, ptCen - vtDir * dRad)) ;
vCenPtg.push_back( make_pair( ptC, ptCen + vtDir * dRad)) ;
vCenPtg.emplace_back( ptC, ptCen - vtDir * dRad) ;
vCenPtg.emplace_back( ptC, ptCen + vtDir * dRad) ;
return 2 ;
}
}
+1 -1
View File
@@ -44,7 +44,7 @@ ChainCurves::AddCurve( int nId, const Point3d& ptStart, const Vector3d& vtStart,
if ( ! m_sCrvId.insert( nId).second)
return true ;
// inserisco i dati della curva nel vettore
m_vCrvData.push_back( CrvData( nId, ptStart, vtStart, ptEnd, vtEnd)) ;
m_vCrvData.emplace_back( nId, ptStart, vtStart, ptEnd, vtEnd) ;
int nV = int( m_vCrvData.size()) ;
// li inserisco nel PointGrid3d
m_PointGrid.InsertPoint( ptStart, nV) ;
+3 -3
View File
@@ -39,7 +39,7 @@ CalcLinePointTgCircle( const Point3d& ptP, const Point3d& ptCen, double dRad, BI
if ( dRad < EPS_SMALL) {
// se la distanza tra i punti è significativa, c'è una soluzione : la retta per i due punti
if ( dDist > EPS_SMALL) {
vBiPnt.push_back( make_pair( ptP, ptCen)) ;
vBiPnt.emplace_back( ptP, ptCen) ;
return 1 ;
}
// altrimenti, nessuna soluzione
@@ -64,12 +64,12 @@ CalcLinePointTgCircle( const Point3d& ptP, const Point3d& ptCen, double dRad, BI
// tangente a destra
Point3d ptT = ptK + vtOrtho ;
ptT.z = ptCen.z ;
vBiPnt.push_back( make_pair( ptP, ptT)) ;
vBiPnt.emplace_back( ptP, ptT) ;
// tangente a sinistra
ptT = ptK - vtOrtho ;
ptT.z = ptCen.z ;
vBiPnt.push_back( make_pair( ptP, ptT)) ;
vBiPnt.emplace_back( ptP, ptT) ;
return 2 ;
}
+1 -1
View File
@@ -1237,7 +1237,7 @@ CurveBezier::GetParamAtLength( double dLen, double& dU) const
double dUFin = 1 ;
while ( ( bOk = GetSegmentParam( dLen, dCurrLen, dSegLen, dUIni, dUFin)) && dSegLen > MIN_SEG_LEN) {
// allungo di un poco l'intervallo di ricerca per compensare l'approssimazione della lunghezza
dUFin = min( dUFin + ( dUFin - dUIni) * 0.05, 1) ;
dUFin = min( dUFin + ( dUFin - dUIni) * 0.05, 1.) ;
}
// aggiustamento finale parametro
if ( bOk)
+2 -2
View File
@@ -136,11 +136,11 @@ CurveByInterp::CalcTangents( int nMethod)
// se ci sono solo 2 punti, le tangenti devono essere dirette lungo la linea che li unisce
if ( nSize == 2) {
// non esiste derivata prima del primo punto
m_vPrevDer.push_back( Vector3d( 0, 0, 0)) ;
m_vPrevDer.emplace_back( 0, 0, 0) ;
m_vNextDer.push_back( ( m_vPnt[1] - m_vPnt[0]) / ( m_vPar[1] - m_vPar[0])) ;
m_vPrevDer.push_back( m_vNextDer[0]) ;
// non esiste derivata dopo il secondo e ultimo punto
m_vNextDer.push_back( Vector3d( 0, 0, 0)) ;
m_vNextDer.emplace_back( 0, 0, 0) ;
return true ;
}
// verifico se curva chiusa (primo e ultimo punto coincidono)
+5 -5
View File
@@ -58,7 +58,7 @@ DistPointArc::DistPointCircle( const Point3d& ptP, const ICurveArc& arArc)
// calcolo del valore di minima distanza
m_dDist = Dist( ptP, ptMinDist) ;
// salvo i dati
m_Info.push_back( MinDistPCInfo( MDPCI_NORMAL, dParam, ptMinDist)) ;
m_Info.emplace_back( MDPCI_NORMAL, dParam, ptMinDist) ;
}
// altrimenti tutti i punti della circonferenza sono a minima distanza
else {
@@ -67,9 +67,9 @@ DistPointArc::DistPointCircle( const Point3d& ptP, const ICurveArc& arArc)
// salvo iniziale e finale, come estremi del range
Point3d ptMinDist ;
arArc.GetStartPoint( ptMinDist) ;
m_Info.push_back( MinDistPCInfo( MDPCI_START_CONT, 0, ptMinDist)) ;
m_Info.emplace_back( MDPCI_START_CONT, 0, ptMinDist) ;
arArc.GetEndPoint( ptMinDist) ;
m_Info.push_back( MinDistPCInfo( MDPCI_END_CONT, 1, ptMinDist)) ;
m_Info.emplace_back( MDPCI_END_CONT, 1, ptMinDist) ;
}
}
@@ -92,7 +92,7 @@ DistPointArc::DistPointFlatArc( const Point3d& ptP, const ICurveArc& arArc)
// altro punto con la stessa minima distanza
if ( i == 1 && fabs( dDist - m_dDist) < EPS_SMALL) {
// lo aggiungo
m_Info.push_back( MinDistPCInfo( MDPCI_NORMAL, dU, ptTest)) ;
m_Info.emplace_back( MDPCI_NORMAL, dU, ptTest) ;
}
// primo punto o punto con minima distanza più bassa
else if ( i == 0 || dDist < m_dDist) {
@@ -100,7 +100,7 @@ DistPointArc::DistPointFlatArc( const Point3d& ptP, const ICurveArc& arArc)
m_dDist = dDist ;
// il nuovo vettore deve contenere solo quest'ultimo minimo
m_Info.clear() ;
m_Info.push_back( MinDistPCInfo( MDPCI_NORMAL, dU, ptTest)) ;
m_Info.emplace_back( MDPCI_NORMAL, dU, ptTest) ;
}
}
}
+2 -2
View File
@@ -169,7 +169,7 @@ FilterMinDistPointCurve( const Point3d& ptP, const ICurve& cCurve,
// se abbastanza lontano e non su bordi intervallino lo aggiungo
if ( SqDist( (*Iter).ptQ, Info.back().ptQ) > MIN_LEN_CONT_MDPC &&
! bLastOnEnd && fabs( (*Iter).dPar - (*Iter).dParMin) > EPS_ZERO) {
Info.push_back( MinDistPCInfo( MDPCI_NORMAL, (*Iter).dPar, (*Iter).ptQ)) ;
Info.emplace_back( MDPCI_NORMAL, (*Iter).dPar, (*Iter).ptQ) ;
bLastOnEnd = fabs( (*Iter).dPar - (*Iter).dParMax) < EPS_ZERO ;
}
// altrimenti lo sostituisco se distanza minore
@@ -185,7 +185,7 @@ FilterMinDistPointCurve( const Point3d& ptP, const ICurve& cCurve,
dMinDist = (*Iter).dDist ;
// il nuovo vettore deve contenere solo quest'ultimo minimo
Info.clear() ;
Info.push_back( MinDistPCInfo( MDPCI_NORMAL, (*Iter).dPar, (*Iter).ptQ)) ;
Info.emplace_back( MDPCI_NORMAL, (*Iter).dPar, (*Iter).ptQ) ;
bLastOnEnd = fabs( (*Iter).dPar - (*Iter).dParMax) < EPS_ZERO ;
}
}
+1 -1
View File
@@ -62,7 +62,7 @@ DistPointCurve::LineCalculate( const Point3d& ptP, const ICurve& Curve, bool bIs
if ( dstPtLn.m_dSqDist >= 0) {
m_dDist = sqrt( dstPtLn.m_dSqDist) ;
m_Info.push_back( MinDistPCInfo( MDPCI_NORMAL, dstPtLn.m_dParam, dstPtLn.m_ptMinDist)) ;
m_Info.emplace_back( MDPCI_NORMAL, dstPtLn.m_dParam, dstPtLn.m_ptMinDist) ;
}
}
BIN
View File
Binary file not shown.
+4 -4
View File
@@ -169,7 +169,7 @@ copy $(TargetPath) \EgtProg\DllD64</Command>
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>Full</Optimization>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;_WINDOWS;I_AM_EGK;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -179,7 +179,7 @@ copy $(TargetPath) \EgtProg\DllD64</Command>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<OmitFramePointers>false</OmitFramePointers>
<OmitFramePointers>true</OmitFramePointers>
<FloatingPointModel>Precise</FloatingPointModel>
</ClCompile>
<Link>
@@ -210,7 +210,7 @@ copy $(TargetPath) \EgtProg\Dll32</Command>
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>Full</Optimization>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;_WINDOWS;I_AM_EGK;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -220,7 +220,7 @@ copy $(TargetPath) \EgtProg\Dll32</Command>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
<OmitFramePointers>false</OmitFramePointers>
<OmitFramePointers>true</OmitFramePointers>
<FloatingPointModel>Precise</FloatingPointModel>
</ClCompile>
<Link>
+4 -4
View File
@@ -360,7 +360,7 @@ NfeFont::ApproxWithLines( const string& sText, int nInsPos, double dLinTol, doub
pCrvNew->Scale( GLOB_FRM, dScaX, dScaY, dScaZ) ;
pCrvNew->Translate( vtMove) ;
// approssimo con linee
lstPL.push_back( PolyLine()) ;
lstPL.emplace_back() ;
pCrvNew->ApproxWithLines( dLinTol, dAngTolDeg, lstPL.back()) ;
}
bIter = pIter->GoToNext() ;
@@ -443,7 +443,7 @@ NfeFont::ApproxWithArcs( const string& sText, int nInsPos, double dLinTol, doubl
pCrvNew->Scale( GLOB_FRM, dScaX, dScaY, dScaZ) ;
pCrvNew->Translate( vtMove) ;
// approssimo con archi
lstPA.push_back( PolyArc()) ;
lstPA.emplace_back() ;
pCrv->ApproxWithArcs( dLinTol, dAngTolDeg, lstPA.back()) ;
}
bIter = pIter->GoToNext() ;
@@ -507,7 +507,7 @@ NfeFont::GetTextLines( const string& sText, int nInsPos, PNTVECTOR& vPt, STRVECT
SetCodePoints( vTmpCode, sLine) ;
vLine.push_back( sLine) ;
vTmpCode.clear() ;
vPt.push_back( Point3d( 0, vtMove.y, 0)) ;
vPt.emplace_back( 0, vtMove.y, 0) ;
}
// sistemo la posizione
vtMove.Set( 0, vtMove.y - dH, 0) ;
@@ -537,7 +537,7 @@ NfeFont::GetTextLines( const string& sText, int nInsPos, PNTVECTOR& vPt, STRVECT
SetCodePoints( vTmpCode, sLine) ;
vLine.push_back( sLine) ;
vTmpCode.clear() ;
vPt.push_back( Point3d( 0, vtMove.y, 0)) ;
vPt.emplace_back( 0, vtMove.y, 0) ;
}
// sistemazioni per la posizione del punto di inserimento
+4 -4
View File
@@ -374,7 +374,7 @@ OsFont::ApproxWithLines( const string& sText, int nInsPos, double dLinTol, doubl
(*iIter)->Scale( GLOB_FRM, dScaX, dScaY, dScaZ) ;
(*iIter)->Translate( vtMove) ;
// approssimo con rette
lstPL.push_back( PolyLine()) ;
lstPL.emplace_back() ;
if ( ! (*iIter)->ApproxWithLines( dLinTol, dAngTolDeg, lstPL.back()))
return false ;
}
@@ -452,7 +452,7 @@ OsFont::ApproxWithArcs( const string& sText, int nInsPos, double dLinTol, double
(*iIter)->Scale( GLOB_FRM, dScaX, dScaY, dScaZ) ;
(*iIter)->Translate( vtMove) ;
// approssimo con archi
lstPA.push_back( PolyArc()) ;
lstPA.emplace_back() ;
if ( ! (*iIter)->ApproxWithArcs( dLinTol, dAngTolDeg, lstPA.back()))
return false ;
}
@@ -522,7 +522,7 @@ OsFont::GetTextLines( const string& sText, int nInsPos, PNTVECTOR& vPt, STRVECTO
SetCodePoints( vTmpCode, sLine) ;
vLine.push_back( sLine) ;
vTmpCode.clear() ;
vPt.push_back( Point3d( 0, vtMove.y, 0)) ;
vPt.emplace_back( 0, vtMove.y, 0) ;
}
// sistemo la posizione
vtMove.Set( 0, vtMove.y - dH, 0) ;
@@ -549,7 +549,7 @@ OsFont::GetTextLines( const string& sText, int nInsPos, PNTVECTOR& vPt, STRVECTO
SetCodePoints( vTmpCode, sLine) ;
vLine.push_back( sLine) ;
vTmpCode.clear() ;
vPt.push_back( Point3d( 0, vtMove.y, 0)) ;
vPt.emplace_back( 0, vtMove.y, 0) ;
}
// sistemazioni per la posizione del punto di inserimento
+1
View File
@@ -15,6 +15,7 @@
#include "/EgtDev/Include/EGkCurve.h"
#include "/EgtDev/Include/EGnStringBase.h"
#define NOMINMAX
#include <Windows.h>
#include <WinGDI.h>
+6 -6
View File
@@ -2124,7 +2124,7 @@ GdbExecutor::ExecuteSurfTriMesh( const string& sCmd2, const STRVECTOR& vsParams)
}
// se creazione per triangolazione di un contorno chiuso e piano
else if ( sCmd2 == "CONT" || sCmd2 == "BYCONTOUR") {
return SurfTriMeshByContour( vsParams) ;
return SurfTriMeshByFlatContour( vsParams) ;
}
// se creazione per estrusione
else if ( sCmd2 == "EXTR" || sCmd2 == "BYEXTRUSION") {
@@ -2321,7 +2321,7 @@ GdbExecutor::SurfTriMeshByTriangleSoup( const STRVECTOR& vsParams)
//----------------------------------------------------------------------------
bool
GdbExecutor::SurfTriMeshByContour( const STRVECTOR& vsParams)
GdbExecutor::SurfTriMeshByFlatContour( const STRVECTOR& vsParams)
{
// 3 o 4 parametri : Id, ParentId, IdCurve[, dLinTol]
if ( vsParams.size() != 3 && vsParams.size() != 4)
@@ -2340,7 +2340,7 @@ GdbExecutor::SurfTriMeshByContour( const STRVECTOR& vsParams)
if ( vsParams.size() == 4)
FromString( vsParams[3], dLinTol) ;
// calcolo la superficie
ISurfTriMesh* pSTM = GetSurfTriMeshByContour( *CrvLoc.Get(), dLinTol) ;
ISurfTriMesh* pSTM = GetSurfTriMeshByFlatContour( CrvLoc.Get(), dLinTol) ;
if ( pSTM == nullptr)
return false ;
// inserisco la superficie trimesh nel DB
@@ -2372,7 +2372,7 @@ GdbExecutor::SurfTriMeshByExtrusion( const STRVECTOR& vsParams)
if ( vsParams.size() == 5)
FromString( vsParams[4], dLinTol) ;
// calcolo la superficie
ISurfTriMesh* pSTM = GetSurfTriMeshByExtrusion( *CrvLoc.Get(), vtExtr, false, dLinTol) ;
ISurfTriMesh* pSTM = GetSurfTriMeshByExtrusion( CrvLoc.Get(), vtExtr, false, dLinTol) ;
if ( pSTM == nullptr)
return false ;
// inserisco la superficie trimesh nel DB
@@ -2405,7 +2405,7 @@ GdbExecutor::SurfTriMeshByTwoPaths( const STRVECTOR& vsParams)
if ( vsParams.size() == 5)
FromString( vsParams[4], dLinTol) ;
// calcolo la superficie
ISurfTriMesh* pSTM = GetSurfTriMeshRuled( *CrvLoc1.Get(), *CrvLoc2.Get(), dLinTol) ;
ISurfTriMesh* pSTM = GetSurfTriMeshRuled( CrvLoc1.Get(), CrvLoc2.Get(), dLinTol) ;
if ( pSTM == nullptr)
return false ;
// inserisco la superficie trimesh nel DB
@@ -2463,7 +2463,7 @@ GdbExecutor::SurfTriMeshByScrewing( bool bMove, const STRVECTOR& vsParams)
if ( ! FromString( vsParams[5], dAngRotDeg))
return false ;
// calcolo la superficie
ISurfTriMesh* pSTM = GetSurfTriMeshByScrewing( *CrvLoc.Get(), ptAx, vtAx, dAngRotDeg, dMove, dLinTol) ;
ISurfTriMesh* pSTM = GetSurfTriMeshByScrewing( CrvLoc.Get(), ptAx, vtAx, dAngRotDeg, dMove, dLinTol) ;
if ( pSTM == nullptr)
return false ;
// inserisco la superficie trimesh nel DB
+1 -1
View File
@@ -106,7 +106,7 @@ class GdbExecutor : public IGdbExecutor
bool SurfTriMeshAddTriangle( const STRVECTOR& vsParams) ;
bool SurfTriMeshEnd( const STRVECTOR& vsParams) ;
bool SurfTriMeshByTriangleSoup( const STRVECTOR& vsParams) ;
bool SurfTriMeshByContour( const STRVECTOR& vsParams) ;
bool SurfTriMeshByFlatContour( const STRVECTOR& vsParams) ;
bool SurfTriMeshByExtrusion( const STRVECTOR& vsParams) ;
bool SurfTriMeshByTwoPaths( const STRVECTOR& vsParams) ;
bool SurfTriMeshByScrewing( bool bMove, const STRVECTOR& vsParams) ;
+6 -6
View File
@@ -252,12 +252,12 @@ CalcLineExtTg2Circles( const Point3d& ptC1, double dRad1, const Point3d& ptC2, d
// offset a sinistra
ptT1 = ptC1 + vtDir ;
ptT2 = ptC2 + vtDir ;
vBiPnt.push_back( make_pair( ptT1, ptT2)) ;
vBiPnt.emplace_back( ptT1, ptT2) ;
++ nSol ;
// offset a destra
ptT1 = ptC1 - vtDir ;
ptT2 = ptC2 - vtDir ;
vBiPnt.push_back( make_pair( ptT1, ptT2)) ;
vBiPnt.emplace_back( ptT1, ptT2) ;
++ nSol ;
}
else if ( nSol1 == 2) {
@@ -269,7 +269,7 @@ CalcLineExtTg2Circles( const Point3d& ptC1, double dRad1, const Point3d& ptC2, d
// punti della prima retta
ptT1 = ptC1 + vtDir ;
ptT2 = vAuxBiPnt[0].second + vtDir ;
vBiPnt.push_back( make_pair( ptT1, ptT2)) ;
vBiPnt.emplace_back( ptT1, ptT2) ;
++ nSol ;
// direzione di offset della seconda retta
vtDir = vAuxBiPnt[1].second - ptC2 ;
@@ -277,7 +277,7 @@ CalcLineExtTg2Circles( const Point3d& ptC1, double dRad1, const Point3d& ptC2, d
// punti della seconda retta
ptT1 = ptC1 + vtDir ;
ptT2 = vAuxBiPnt[1].second + vtDir ;
vBiPnt.push_back( make_pair( ptT1, ptT2)) ;
vBiPnt.emplace_back( ptT1, ptT2) ;
++ nSol ;
}
@@ -309,7 +309,7 @@ CalcLineIntTg2Circles( const Point3d& ptC1, double dRad1, const Point3d& ptC2, d
// punti della prima retta
ptT1 = ptC1 + vtDir ;
ptT2 = vAuxBiPnt[0].second + vtDir ;
vBiPnt.push_back( make_pair( ptT1, ptT2)) ;
vBiPnt.emplace_back( ptT1, ptT2) ;
++ nSol ;
// direzione di offset della seconda retta
vtDir = ptC2 - vAuxBiPnt[1].second ;
@@ -317,7 +317,7 @@ CalcLineIntTg2Circles( const Point3d& ptC1, double dRad1, const Point3d& ptC2, d
// punti della seconda retta
ptT1 = ptC1 + vtDir ;
ptT2 = vAuxBiPnt[1].second + vtDir ;
vBiPnt.push_back( make_pair( ptT1, ptT2)) ;
vBiPnt.emplace_back( ptT1, ptT2) ;
++ nSol ;
}
+46 -2
View File
@@ -146,7 +146,7 @@ PointGrid3d::InsertPoint( const Point3d& ptP, int nId)
{
// inserimento nel map
int nKey = PointHash( Get1dCellNbr( ptP.x), Get1dCellNbr( ptP.y), Get1dCellNbr( ptP.z)) ;
m_MMap.insert( make_pair( nKey, make_pair( ptP, nId))) ;
m_MMap.emplace( nKey, make_pair( ptP, nId)) ;
// aggiornamento del bbox complessivo
m_BBox.Add( ptP) ;
return true ;
@@ -198,6 +198,32 @@ PointGrid3d::Find( const Point3d& ptTest, double dTol, INTVECTOR& vnIds)
return ( vnIds.size() > 0) ;
}
//----------------------------------------------------------------------------
bool
PointGrid3d::Find( const BBox3d& b3Test, INTVECTOR& vnIds)
{
// pulisco il risultato
vnIds.clear() ;
// determino il range di celle sui tre assi
IBox iBox ;
if ( ! Get3dRangeNbr( b3Test, iBox))
return false ;
// ciclo su tutte le celle del range
for ( int i = iBox.nXmin ; i <= iBox.nXmax ; ++ i) {
for ( int j = iBox.nYmin ; j <= iBox.nYmax ; ++ j) {
for ( int k = iBox.nZmin ; k <= iBox.nZmax ; ++ k) {
IPNTI_UMMAP_CRANGE MMrange = m_MMap.equal_range( PointHash( i, j, k)) ;
for ( ; MMrange.first != MMrange.second ; ++ MMrange.first) {
if ( b3Test.Encloses( (*MMrange.first).second.first))
vnIds.push_back( (*MMrange.first).second.second) ;
}
}
}
}
return ( vnIds.size() > 0) ;
}
//----------------------------------------------------------------------------
bool
PointGrid3d::Find( const Point3d& ptTest, double dTol, int& nId)
@@ -315,6 +341,24 @@ PointGrid3d::Get1dCellNbr( double dCoord)
return static_cast<int>( floor( dCoord * m_dInvCellDim)) ;
}
//----------------------------------------------------------------------------
bool
PointGrid3d::Get3dRangeNbr( const BBox3d& b3Test, IBox& iBox)
{
// calcolo intersezione tra box
BBox3d b3Int ;
if ( ! m_BBox.FindIntersection( b3Test, b3Int))
return false ;
// ricavo gli indici sui tre assi degli estremi del box
iBox.nXmin = Get1dCellNbr( b3Int.GetMin().x) ;
iBox.nYmin = Get1dCellNbr( b3Int.GetMin().y) ;
iBox.nZmin = Get1dCellNbr( b3Int.GetMin().z) ;
iBox.nXmax = Get1dCellNbr( b3Int.GetMax().x) ;
iBox.nYmax = Get1dCellNbr( b3Int.GetMax().y) ;
iBox.nZmax = Get1dCellNbr( b3Int.GetMax().z) ;
return true ;
}
//----------------------------------------------------------------------------
bool
PointGrid3d::Get3dRangeNbr( const Point3d& ptTest, double dTol, IBox& iBox)
@@ -337,5 +381,5 @@ PointGrid3d::Get3dRangeNbr( const Point3d& ptTest, double dTol, IBox& iBox)
int
PointGrid3d::PointHash( int nX, int nY, int nZ)
{
return ( nX * 73856093 ^ nY * 19349663 ^ nZ * 83492791) ;
return ( nX * 73856093 ^ nY * 19349653 ^ nZ * 83492791) ;
}
+1 -1
View File
@@ -64,7 +64,7 @@ PolyArc::AddUPoint( double dPar, const Point3d& ptP, double dBulge)
return true ;
}
try {
m_lUPointBs.push_back( UPointB( dPar, ptP, dBulge)) ;
m_lUPointBs.emplace_back( dPar, ptP, dBulge) ;
}
catch (...) {
return false ;
+15 -1
View File
@@ -55,7 +55,7 @@ PolyLine::AddUPoint( double dPar, const Point3d& ptP)
}
// eseguo inserimento
try {
m_lUPoints.push_back( POINTU( ptP, dPar)) ;
m_lUPoints.emplace_back( ptP, dPar) ;
}
catch (...) {
return false ;
@@ -258,6 +258,20 @@ PolyLine::Split( double dU, PolyLine& PL)
return true ;
}
//----------------------------------------------------------------------------
bool
PolyLine::GetLocalBBox( BBox3d& b3Loc) const
{
// assegno il box in locale, scorrendo tutti i punti
b3Loc.Reset() ;
for ( PNTULIST::const_iterator iter = m_lUPoints.begin() ;
iter != m_lUPoints.end() ;
++ iter)
b3Loc.Add( iter->first) ;
return true ;
}
//----------------------------------------------------------------------------
bool
PolyLine::IsClosed( void) const
+2 -2
View File
@@ -29,7 +29,7 @@ PolynomialPoint3d::SetDegree( int nDegree)
m_Coeff.reserve( nDegree + 1) ;
m_nDegree = nDegree ;
for ( int i = 0 ; i <= m_nDegree ; ++ i)
m_Coeff.push_back( Point3d( 0, 0, 0)) ;
m_Coeff.emplace_back( 0, 0, 0) ;
return true ;
}
catch (...) {
@@ -48,7 +48,7 @@ PolynomialPoint3d::EnsureDegree( int nDegree)
try {
m_Coeff.reserve( nDegree + 1) ;
for ( int i = m_nDegree + 1 ; i <= nDegree ; ++ i)
m_Coeff.push_back( Point3d()) ;
m_Coeff.emplace_back() ;
m_nDegree = nDegree ;
return true ;
}
+158 -16
View File
@@ -20,16 +20,20 @@
using namespace std ;
//-------------------------------------------------------------------------------
static bool CalcRegionPolyLines( const ICURVEPVECTOR& vpCurve, double dLinTol,
POLYLINEVECTOR& vPL, Vector3d& vtN) ;
//-------------------------------------------------------------------------------
ISurfTriMesh*
GetSurfTriMeshByContour( const ICurve& Curve, double dLinTol)
GetSurfTriMeshByFlatContour( const ICurve* pCurve, double dLinTol)
{
// verifica parametri
if ( &Curve == nullptr)
if ( pCurve == nullptr)
return nullptr ;
// calcolo la polilinea che approssima la curva
PolyLine PL ;
if ( ! Curve.ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL))
if ( ! pCurve->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL))
return nullptr ;
// creo e setto la superficie trimesh
PtrOwner<ISurfTriMesh> pSTM( CreateSurfTriMesh()) ;
@@ -41,15 +45,35 @@ GetSurfTriMeshByContour( const ICurve& Curve, double dLinTol)
//-------------------------------------------------------------------------------
ISurfTriMesh*
GetSurfTriMeshByExtrusion( const ICurve& Curve, const Vector3d& vtExtr,
GetSurfTriMeshByRegion( const ICURVEPVECTOR& vpCurve, double dLinTol)
{
// verifica parametri
if ( &vpCurve == nullptr || vpCurve.empty())
return nullptr ;
// calcolo le polilinee che approssimano le curve della regione
POLYLINEVECTOR vPL ;
Vector3d vtN ;
if ( ! CalcRegionPolyLines( vpCurve, dLinTol, vPL, vtN))
return nullptr ;
// creo e setto la superficie trimesh
PtrOwner<ISurfTriMesh> pSTM( CreateSurfTriMesh()) ;
if ( IsNull( pSTM) || ! pSTM->CreateByRegion( vPL))
return nullptr ;
// restituisco la superficie
return Release( pSTM) ;
}
//-------------------------------------------------------------------------------
ISurfTriMesh*
GetSurfTriMeshByExtrusion( const ICurve* pCurve, const Vector3d& vtExtr,
bool bCapEnds, double dLinTol)
{
// verifica parametri
if ( &Curve == nullptr || &vtExtr == nullptr)
if ( pCurve == nullptr || &vtExtr == nullptr)
return nullptr ;
// calcolo la polilinea che approssima la curva
PolyLine PL ;
if ( ! Curve.ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL))
if ( ! pCurve->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL))
return nullptr ;
// se richiesta chiusura agli estremi
bool bDoCapEnds = false ;
@@ -62,6 +86,7 @@ GetSurfTriMeshByExtrusion( const ICurve& Curve, const Vector3d& vtExtr,
double dOrthoExtr = plPlane.vtN * vtExtr ;
if ( ( fabs( dOrthoExtr) > EPS_SMALL)) {
bDoCapEnds = true ;
// se negativa, inverto il senso del contorno
if ( dOrthoExtr < 0)
PL.Invert() ;
}
@@ -95,17 +120,75 @@ GetSurfTriMeshByExtrusion( const ICurve& Curve, const Vector3d& vtExtr,
//-------------------------------------------------------------------------------
ISurfTriMesh*
GetSurfTriMeshByRevolve( const ICurve& Curve, const Point3d& ptAx, const Vector3d& vtAx,
GetSurfTriMeshByRegionExtrusion( const ICURVEPVECTOR& vpCurve, const Vector3d& vtExtr, double dLinTol)
{
// verifica parametri
if ( &vpCurve == nullptr || vpCurve.empty() || &vtExtr == nullptr)
return nullptr ;
// se una sola curva, uso la funzione precedente
if ( vpCurve.size() == 1 )
return GetSurfTriMeshByExtrusion( vpCurve[0], vtExtr, true, dLinTol) ;
// calcolo le polilinee che approssimano le curve della regione
POLYLINEVECTOR vPL ;
Vector3d vtN ;
if ( ! CalcRegionPolyLines( vpCurve, dLinTol, vPL, vtN))
return nullptr ;
// verifico la direzione di estrusione
double dOrthoExtr = vtN * vtExtr ;
if ( ( fabs( dOrthoExtr) < EPS_SMALL))
return nullptr ;
// se componente estrusione negativa, inverto tutti i percorsi
if ( dOrthoExtr < 0) {
for ( int i = 0 ; i < int( vPL.size()) ; ++ i)
vPL[i].Invert() ;
}
// creo la prima superficie di estremità
PtrOwner<ISurfTriMesh> pSTM( CreateSurfTriMesh()) ;
if ( IsNull( pSTM) || ! pSTM->CreateByRegion( vPL))
return nullptr ;
// creo la seconda superficie e la unisco alla prima
{ // copio la prima superficie
PtrOwner<ISurfTriMesh> pSTM2( GetSurfTriMesh( pSTM->Clone())) ;
if ( IsNull( pSTM2))
return nullptr ;
// inverto la prima superficie
pSTM->Invert() ;
// traslo la seconda
pSTM2->Translate( vtExtr) ;
// la unisco alla prima
if ( ! pSTM->DoSewing( *pSTM2))
return nullptr ;
}
// creo e unisco le diverse superfici di estrusione
for ( int i = 0 ; i < int( vPL.size()) ; ++ i) {
// estrusione
PtrOwner<ISurfTriMesh> pSTM2( CreateSurfTriMesh()) ;
if ( IsNull( pSTM2) || ! pSTM2->CreateByExtrusion( vPL[i], vtExtr))
return nullptr ;
// la unisco alla superficie principale
if ( ! pSTM->DoSewing( *pSTM2))
return nullptr ;
}
// compatto la superficie
if ( ! pSTM->DoCompacting())
return nullptr ;
// restituisco la superficie
return Release( pSTM) ;
}
//-------------------------------------------------------------------------------
ISurfTriMesh*
GetSurfTriMeshByRevolve( const ICurve* pCurve, const Point3d& ptAx, const Vector3d& vtAx,
bool bCapEnds, double dLinTol)
{
// verifica parametri
if ( &Curve == nullptr || &ptAx == nullptr || &vtAx == nullptr)
if ( pCurve == nullptr || &ptAx == nullptr || &vtAx == nullptr)
return nullptr ;
// limite minimo su tolleranza
dLinTol = max( dLinTol, EPS_SMALL) ;
// calcolo la polilinea che approssima la curva
PolyLine PL ;
if ( ! Curve.ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL))
if ( ! pCurve->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL))
return nullptr ;
// calcolo lo step di rotazione
double dMaxRad = 0 ;
@@ -156,17 +239,17 @@ GetSurfTriMeshByRevolve( const ICurve& Curve, const Point3d& ptAx, const Vector3
//-------------------------------------------------------------------------------
ISurfTriMesh*
GetSurfTriMeshByScrewing( const ICurve& Curve, const Point3d& ptAx, const Vector3d& vtAx,
GetSurfTriMeshByScrewing( const ICurve* pCurve, const Point3d& ptAx, const Vector3d& vtAx,
double dAngRotDeg, double dMove, double dLinTol)
{
// verifica parametri
if ( &Curve == nullptr || &ptAx == nullptr || &vtAx == nullptr)
if ( pCurve == nullptr || &ptAx == nullptr || &vtAx == nullptr)
return nullptr ;
// limite minimo su tolleranza
dLinTol = max( dLinTol, EPS_SMALL) ;
// calcolo la polilinea che approssima la curva
PolyLine PL ;
if ( ! Curve.ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL))
if ( ! pCurve->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL))
return nullptr ;
// calcolo lo step di rotazione
double dMaxRad = 0 ;
@@ -189,18 +272,18 @@ GetSurfTriMeshByScrewing( const ICurve& Curve, const Point3d& ptAx, const Vector
//-------------------------------------------------------------------------------
ISurfTriMesh*
GetSurfTriMeshRuled( const ICurve& Curve1, const ICurve& Curve2, double dLinTol)
GetSurfTriMeshRuled( const ICurve* pCurve1, const ICurve* pCurve2, double dLinTol)
{
// verifica parametri
if ( &Curve1 == nullptr || &Curve2 == nullptr)
if ( pCurve1 == nullptr || pCurve2 == nullptr)
return nullptr ;
// calcolo la polilinea che approssima la prima curva
PolyLine PL1 ;
if ( ! Curve1.ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL1))
if ( ! pCurve1->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL1))
return nullptr ;
// calcolo la polilinea che approssima la seconda curva
PolyLine PL2 ;
if ( ! Curve2.ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL2))
if ( ! pCurve2->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL2))
return nullptr ;
// creo e setto la superficie trimesh
PtrOwner<ISurfTriMesh> pSTM( CreateSurfTriMesh()) ;
@@ -209,3 +292,62 @@ GetSurfTriMeshRuled( const ICurve& Curve1, const ICurve& Curve2, double dLinTol)
// restituisco la superficie
return Release( pSTM) ;
}
//-------------------------------------------------------------------------------
bool
CalcRegionPolyLines( const ICURVEPVECTOR& vpCurve, double dLinTol,
POLYLINEVECTOR& vPL, Vector3d& vtN)
{
// calcolo le polilinee che approssimano le curve
POLYLINEVECTOR vPLtmp ;
vPLtmp.resize( vpCurve.size()) ;
for ( int i = 0 ; i < int( vpCurve.size()) ; ++ i) {
if ( ! vpCurve[i]->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, vPLtmp[i]))
return nullptr ;
}
// ne calcolo l'area e genero un ordine in senso decrescente
typedef std::pair<int,double> INDAREA ; // coppia indice, area
typedef std::vector<INDAREA> INDAREAVECTOR ; // vettore di coppie indice, area
INDAREAVECTOR vArea ;
vArea.reserve( vPLtmp.size()) ;
Vector3d vtN0 ;
for ( int i = 0 ; i < int( vPLtmp.size()) ; ++ i) {
// verifico chiusura, calcolo piano medio e area
Plane3d plPlane ;
double dArea ;
if ( ! vPLtmp[i].IsClosedAndFlat( plPlane, dArea, 50 * EPS_SMALL))
return false ;
// imposto la normale del primo contorno come riferimento
if ( i == 0)
vtN0 = plPlane.vtN ;
// verifico che le normali siano molto vicine
if ( ! AreSameOrOppositeVectorApprox( plPlane.vtN, vtN0))
return false ;
// assegno il segno all'area secondo il verso della normale
if ( ( plPlane.vtN * vtN0) > 0)
vArea.emplace_back( i, dArea) ;
else
vArea.emplace_back( i, - dArea) ;
}
sort( vArea.begin(), vArea.end(),
[]( const INDAREA& a, const INDAREA&b) { return fabs( a.second) > fabs( b.second) ; }) ;
// sposto le polilinee nel vettore da restituire secondo l'ordine
vPL.clear() ;
vPL.resize( vPLtmp.size()) ;
bool bCCW = true ;
for ( int i = 0 ; i < int( vPLtmp.size()) ; ++ i) {
// scambio
swap( vPL[i], vPLtmp[vArea[i].first]) ;
// verifico senso di rotazione del contorno esterno
if ( i == 0)
bCCW = ( vArea[i].second > 0) ;
// aggiusto gli altri contorni
else {
if ( ( bCCW && vArea[i].second > 0) || ( ! bCCW && vArea[i].second < 0))
vPL[i].Invert() ;
}
}
// restituisco la normale positiva alla regione
vtN = ( bCCW ? vtN0 : - vtN0) ;
return true ;
}
+39 -2
View File
@@ -75,7 +75,7 @@ SurfTriMesh::AddVertex( const Point3d& ptVert)
m_nStatus = TO_VERIFY ;
m_OGrMgr.Reset() ;
// inserisco il vertice
try { m_vVert.push_back( StmVert( ptVert)) ;}
try { m_vVert.emplace_back( ptVert) ;}
catch(...) { return SVT_NULL ;}
// ne determino l'indice
return int( m_vVert.size() - 1) ;
@@ -138,7 +138,7 @@ SurfTriMesh::AddTriangle( const int nIdVert[3])
m_nStatus = TO_VERIFY ;
m_OGrMgr.Reset() ;
// inserisco il triangolo
try { m_vTria.push_back( StmTria( nIdVert)) ;}
try { m_vTria.emplace_back( nIdVert) ;}
catch(...) { return SVT_NULL ;}
// ne determino l'indice
return int( m_vTria.size() - 1) ;
@@ -871,6 +871,43 @@ SurfTriMesh::CreateByFlatContour( const PolyLine& PL)
return AdjustTopology() ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::CreateByRegion( const POLYLINEVECTOR& vPL)
{
// eseguo la triangolazione, dopo aver verificato che l'insieme di contorni costituisca una regione
PNTVECTOR vPnt ;
INTVECTOR vTria ;
Triangulate Tri ;
if ( ! Tri.Make( vPL, vPnt, vTria))
return false ;
// inizializzo la superficie
int nVert = int( vPnt.size()) ;
int nTria = int( vTria.size()) / 3 ;
if ( ! Init( nVert, nTria))
return false ;
// inserisco i vertici nella superficie
for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) {
if ( AddVertex( vPnt[i]) == SVT_NULL)
return false ;
}
// recupero i triangoli e li inserisco nella superficie
int vV[3] ;
for ( int i = 0 ; i < nTria ; ++i) {
vV[0] = vTria[3*i] ;
vV[1] = vTria[3*i+1] ;
vV[2] = vTria[3*i+2] ;
if ( AddTriangle( vV) == SVT_NULL)
return false ;
}
// compatto e sistemo la topologia
return AdjustTopology() ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::CreateByExtrusion( const PolyLine& PL, const Vector3d& vtExtr)
+1 -1
View File
@@ -17,7 +17,6 @@
#include "DllMain.h"
#include "GeoObjRW.h"
#include "/EgtDev/Include/EGkSurfTriMesh.h"
#include "/EgtDev/Include/EgtNumCollection.h"
#include <algorithm>
//----------------------------------------------------------------------------
@@ -110,6 +109,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
virtual int AddTriangle( const int nIdVert[3]) ;
virtual bool AdjustTopology( void) ;
virtual bool CreateByFlatContour( const PolyLine& PL) ;
virtual bool CreateByRegion( const POLYLINEVECTOR& vPL) ;
virtual bool CreateByExtrusion( const PolyLine& PL, const Vector3d& vtExtr) ;
virtual bool CreateByTwoCurves( const PolyLine& PL1, const PolyLine& PL2) ;
virtual bool CreateByRevolution( const PolyLine& PL, const Point3d& ptAx, const Vector3d& vtAx,
+729 -91
View File
@@ -13,12 +13,24 @@
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include <algorithm>
#include "Triangulate.h"
#include "\EgtDev\Include\EGkPolyLine.h"
#include "\EgtDev\Include\EGkPlane3d.h"
#include "DllMain.h"
#include "/EgtDev/Include/EGkStringUtils3d.h"
#include "/EgtDev/Include/EgtLogger.h"
using namespace std ;
//----------------------------------------------------------------------------
static enum PlaneType { PL_XY = 1, PL_YZ = 2, PL_ZX = 3} ;
static enum EarStatus{ EAS_NULL = -1, EAS_NO = 0, EAS_OK = 1} ;
//----------------------------------------------------------------------------
static bool ChangeStartPntVector( int nNewStart, PNTVECTOR& vPi) ;
//----------------------------------------------------------------------------
// In : PolyLine
// Out : PNTVECTOR (Point3d Vector) : points of the polyline
@@ -56,20 +68,15 @@ Triangulate::Make( const PolyLine& PL, PNTVECTOR& vPt, INTVECTOR& vTr)
// inserisco i punti
while ( PL.GetNextPoint( ptP))
vPt.push_back( ptP) ;
// se non CCW inverto il vettore dei punti
if ( ! bCCW)
reverse( vPt.begin(), vPt.end()) ;
// creo il vettore degli indici del Poligono
INTVECTOR vPol ;
int n = int( vPt.size()) ;
vPol.reserve( n) ;
// se orientato correttamente (componente di N > 0)
if ( bCCW) {
for ( int i = 0 ; i < n ; ++ i)
vPol.push_back( i) ;
}
// altrimenti lo prendo al contrario
else {
for ( int i = n - 1 ; i >= 0 ; -- i)
vPol.push_back( i) ;
}
for ( int i = 0 ; i < n ; ++ i)
vPol.push_back( i) ;
// eseguo la triangolazione
if ( ! MakeByEC2( vPt, vPol, vTr))
@@ -82,6 +89,153 @@ Triangulate::Make( const PolyLine& PL, PNTVECTOR& vPt, INTVECTOR& vTr)
return true ;
}
//----------------------------------------------------------------------------
// In : POLYLINEVECTOR : vector of polylines, the first outer, the others inner
// Out : PNTVECTOR (Point3d Vector) : points of the polyline
// INTVECTOR (int Vector) : 3*T indices of above points for T triangles
//----------------------------------------------------------------------------
bool
Triangulate::Make( const POLYLINEVECTOR& vPL, PNTVECTOR& vPt, INTVECTOR& vTr)
{
// pulisco i vettori di ritorno
vPt.clear() ;
vTr.clear() ;
// ci devono essere delle polilinee nel vettore
if ( &vPL == nullptr || vPL.empty())
return false ;
// se una sola polilinea mi riconduco al caso precedente
if ( vPL.size() == 1)
return Make( vPL[0], vPt, vTr) ;
// verifico che la polilinea esterna sia chiusa e piana e calcolo il piano medio del poligono
double dArea ;
Plane3d plExtPlane ;
if ( ! vPL[0].IsClosedAndFlat( plExtPlane, dArea, 50 * EPS_SMALL))
return false ;
bool bCCW ;
if ( fabs( plExtPlane.vtN.z) >= fabs( plExtPlane.vtN.x) &&
fabs( plExtPlane.vtN.z) >= fabs( plExtPlane.vtN.y)) {
m_nPlane = PL_XY ;
bCCW = ( plExtPlane.vtN.z > 0) ;
}
else if ( fabs( plExtPlane.vtN.x) >= fabs( plExtPlane.vtN.y)) {
m_nPlane = PL_YZ ;
bCCW = ( plExtPlane.vtN.x > 0) ;
}
else {
m_nPlane = PL_ZX ;
bCCW = ( plExtPlane.vtN.y > 0) ;
}
// verifico le altre polilinee
for ( int i = 1 ; i < int( vPL.size()) ; ++i) {
// deve essere chiusa, giacere nello stesso piano ed essere orientata al contrario della esterna
double dArea ;
Plane3d plPlane ;
if ( ! vPL[i].IsClosedAndFlat( plPlane, dArea, 50 * EPS_SMALL) ||
! AreOppositeVectorApprox( plExtPlane.vtN, plPlane.vtN))
return false ;
}
// se non CCW inverto tutte le polilinee
if ( ! bCCW) {
for ( int i = 0 ; i < int( vPL.size()) ; ++i)
const_cast<PolyLine&>(vPL[i]).Invert( true) ;
}
// calcolo ordine decrescente su Xmax o Ymax o Zmax secondo m_nPlane per le curve interne
INTVECTOR vOrd ;
if ( ! SortInternalLoops( vPL, vOrd))
return false ;
// riempio il vettore con i punti dei poligoni da triangolare
// calcolo spazio totale e spazio massimo per un percorso interno
int nTot = vPL[0].GetPointNbr() - 1 ;
int nMax = 0 ;
for ( int i = 1 ; i < int( vPL.size()) ; ++i) {
nTot += vPL[i].GetPointNbr() + 1 ;
if ( vPL[i].GetPointNbr() > nMax)
nMax = vPL[i].GetPointNbr() ;
}
// riservo spazio pari al totale dei punti (anche quelli ripetuti di chiusura che servono per i link)
vPt.reserve( nTot) ;
// inserisco i punti del contorno esterno (tranne il primo che coincide con l'ultimo)
if ( ! GetPntVectorFromPolyline( vPL[0], false, vPt))
return false ;
// ciclo sui percorsi interni ordinati secondo Xmax decrescente
PNTVECTOR vPi ;
vPi.reserve( nMax) ;
for ( int i = 1 ; i < int( vPL.size()) ; ++ i) {
// riordino il percorso per avere punto iniziale con Xmax
if ( ! GetPntVectorFromPolyline( vPL[vOrd[i]], true, vPi))
return false ;
// cerco un punto del percorso esterno visibile dal punto iniziale del precedente interno
int nI ;
if ( ! GetOuterPntToJoin( vPt, vPi[0], nI))
return false ;
// riordino percorso esterno per avere questo punto all'inizio
if ( ! ChangeStartPntVector( nI, vPt))
return false ;
// ripeto punto iniziale
vPt.push_back( vPt[0]) ;
// accodo percorso interno
for ( int j = 0 ; j < int( vPi.size()) ; ++j)
vPt.push_back( vPi[j]) ;
// ripeto punto iniziale di percorso interno
vPt.push_back( vPi[0]) ;
// cancello percorso interno
vPi.clear() ;
}
// ripristino l'orientamento delle polilinee originali per il caso non CCW
if ( ! bCCW) {
for ( int i = 0 ; i < int( vPL.size()) ; ++i)
const_cast<PolyLine&>(vPL[i]).Invert( true) ;
}
// creo il vettore degli indici del Poligono
INTVECTOR vPol ;
int n = int( vPt.size()) ;
vPol.reserve( n) ;
// non devo gestire separatamente CCW perchè ho già invertito i punti
for ( int i = 0 ; i < n ; ++ i)
vPol.push_back( i) ;
// eseguo la triangolazione
if ( ! MakeByEC2( vPt, vPol, vTr))
return false ;
// se era CW, devo invertire il senso dei triangoli
if ( ! bCCW)
reverse( vTr.begin(), vTr.end()) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Triangulate::PrepareGrid( const PNTVECTOR& vPt, const INTVECTOR& vPol,
const INTVECTOR& vPrev, const INTVECTOR& vNext)
{
// points number
int n = int( vPol.size()) ;
// overall box
BBox3d b3All ;
for ( int j = 0 ; j < n ; ++ j)
b3All.Add( vPt[vPol[j]]) ;
// grid cell dimension
double dCellDim ;
b3All.GetRadius( dCellDim) ;
dCellDim *= 2 / sqrt( n) ;
// grid
if ( ! m_VertGrid.Init( 2 * n, dCellDim))
return false ;
for ( int j = 0 ; j < n ; ++ j) {
// insert only reflex vertex
if ( ! TriangleIsCCW( vPt[vPol[vPrev[j]]], vPt[vPol[j]], vPt[vPol[vNext[j]]])) {
if ( ! m_VertGrid.InsertPoint( vPt[vPol[j]], j))
return false ;
}
}
m_vVert.reserve( n / 5) ;
return true ;
}
//----------------------------------------------------------------------------
// Triangulate the CCW n-gon specified by the vertices vPt (Pt[n] != Pt[0])
// Ear Clipping algorithm
@@ -114,19 +268,27 @@ Triangulate::MakeByEC( const PNTVECTOR& vPt, const INTVECTOR& vPol, INTVECTOR& v
int i = 0 ;
int nCount = n ;
// Keep removing vertices until just a triangle left
while ( n > 3) {
while ( n >= 3) {
// To avoid infinite loop
if ( nCount <= 0)
return false ;
-- nCount ;
// Test if current vertex, v[i], is an ear
bool bIsEar = TestTriangle( vPt, vPol, vPrev, vNext, i) ;
bool bSave = bIsEar ;
// Verify if triangle is null (accept to discard)
if ( ! bIsEar) {
if ( Collinear( vPt[vPol[vPrev[i]]], vPt[vPol[i]], vPt[vPol[vNext[i]]]))
bIsEar = true ;
}
// If current vertex v[i] is an ear, delete it and visit the previous vertex
if ( bIsEar) {
// Triangle (v[prev[i]], v[i], v[next[i]]) is an ear
vTr.push_back( vPol[vPrev[i]]) ;
vTr.push_back( vPol[i]) ;
vTr.push_back( vPol[vNext[i]]) ;
if ( bSave) {
vTr.push_back( vPol[vPrev[i]]) ;
vTr.push_back( vPol[i]) ;
vTr.push_back( vPol[vNext[i]]) ;
}
// Delete vertex v[i] by redirecting next and previous links
// of neighboring verts past it. Decrement vertex count
vNext[vPrev[i]] = vNext[i] ;
@@ -142,17 +304,13 @@ Triangulate::MakeByEC( const PNTVECTOR& vPt, const INTVECTOR& vPol, INTVECTOR& v
i = vNext[i] ;
}
}
// Last triangle is an ear
vTr.push_back( vPol[vPrev[i]]) ;
vTr.push_back( vPol[i]) ;
vTr.push_back( vPol[vNext[i]]) ;
return true ;
}
//----------------------------------------------------------------------------
// Triangulate the CCW n-gon specified by the vertices vPt (Pt[n] != Pt[0])
// Ear Clipping algorithm enhanced
// Ear Clipping algorithm enhanced, choose smaller diagonal
//----------------------------------------------------------------------------
bool
Triangulate::MakeByEC2( const PNTVECTOR& vPt, const INTVECTOR& vPol, INTVECTOR& vTr)
@@ -178,39 +336,53 @@ Triangulate::MakeByEC2( const PNTVECTOR& vPt, const INTVECTOR& vPol, INTVECTOR&
vPrev[0] = n - 1 ;
vNext[n-1] = 0 ;
// Prepare Ear status vector
INTVECTOR vEar( n, EAS_NULL) ;
// Prepare PointGrid
if ( ! PrepareGrid( vPt, vPol, vPrev, vNext))
return false ;
// Start at vertex 0
int i = 0 ;
int nCount = n ;
// Keep removing vertices until just a triangle left
while ( n > 3) {
while ( n >= 3) {
// To avoid infinite loop
if ( nCount <= 0)
return false ;
-- nCount ;
// Test if current vertex, v[i], is an ear
bool bIsEar = TestTriangle( vPt, vPol, vPrev, vNext, i) ;
if ( vEar[i] == EAS_NULL)
vEar[i] = ( TestTriangle( vPt, vPol, vPrev, vNext, i) ? EAS_OK : EAS_NO) ;
bool bIsEar = ( vEar[i] == EAS_OK) ;
bool bSave = bIsEar ;
if ( bIsEar) {
// Save square distance of diagonal
double dSqDist = SqDist(vPt[vPol[vPrev[i]]], vPt[vPol[vNext[i]]]) ;
// Try with next or next^2
int j = vNext[i] ;
// Try with 3 next
int j = i ;
double dSqDist1 = INFINITO ;
if ( TestTriangle( vPt, vPol, vPrev, vNext, j))
dSqDist1 = SqDist( vPt[vPol[vPrev[j]]], vPt[vPol[vNext[j]]]) ;
else {
for ( int h = 0 ; h < 3 ; ++ h) {
j = vNext[j] ;
if ( TestTriangle( vPt, vPol, vPrev, vNext, j))
if ( vEar[j] == EAS_NULL)
vEar[j] = ( TestTriangle( vPt, vPol, vPrev, vNext, j) ? EAS_OK : EAS_NO) ;
if ( vEar[j] == EAS_OK) {
dSqDist1 = SqDist( vPt[vPol[vPrev[j]]], vPt[vPol[vNext[j]]]) ;
break ;
}
}
// Try with prev or prev^2
int k = vPrev[i] ;
// Try with 3 prev
int k = i ;
double dSqDist2 = INFINITO ;
if ( TestTriangle( vPt, vPol, vPrev, vNext, k))
dSqDist2 = SqDist( vPt[vPol[vPrev[k]]], vPt[vPol[vNext[k]]]) ;
else {
for ( int h = 0 ; h < 3 ; ++ h) {
k = vPrev[k] ;
if ( TestTriangle( vPt, vPol, vPrev, vNext, k))
if ( vEar[k] == EAS_NULL)
vEar[k] = ( TestTriangle( vPt, vPol, vPrev, vNext, k) ? EAS_OK : EAS_NO) ;
if ( vEar[k] == EAS_OK) {
dSqDist2 = SqDist( vPt[vPol[vPrev[k]]], vPt[vPol[vNext[k]]]) ;
break ;
}
}
// Choose the better (EPS_ZERO to have a difference)
if ( dSqDist < dSqDist1 + EPS_ZERO && dSqDist < dSqDist2 + EPS_ZERO)
@@ -220,32 +392,151 @@ Triangulate::MakeByEC2( const PNTVECTOR& vPt, const INTVECTOR& vPol, INTVECTOR&
else
i = k ;
}
// Verify if triangle is null (accept to discard)
else {
if ( Collinear( vPt[vPol[vPrev[i]]], vPt[vPol[i]], vPt[vPol[vNext[i]]]) &&
! Aligned( vPt[vPol[vPrev[i]]], vPt[vPol[i]], vPt[vPol[vNext[i]]]))
bIsEar = true ;
}
// If current vertex v[i] is an ear, delete it and visit the previous vertex
if ( bIsEar) {
// Triangle (v[prev[i]], v[i], v[next[i]]) is an ear
vTr.push_back( vPol[vPrev[i]]) ;
vTr.push_back( vPol[i]) ;
vTr.push_back( vPol[vNext[i]]) ;
// Delete vertex v[i] by redirecting next and previous links
// of neighboring verts past it. Decrement vertex count
vNext[vPrev[i]] = vNext[i] ;
vPrev[vNext[i]] = vPrev[i] ;
n--;
// Visit the previous vertex next
i = vPrev[i] ;
// Reset Count
nCount = n ;
// Triangle (v[prev[i]], v[i], v[next[i]]) is an ear
if ( bSave) {
vTr.push_back( vPol[vPrev[i]]) ;
vTr.push_back( vPol[i]) ;
vTr.push_back( vPol[vNext[i]]) ;
}
// Reset earity of diagonal endpoints
vEar[vPrev[i]] = EAS_NULL ;
vEar[vNext[i]] = EAS_NULL ;
// Delete vertex v[i] by redirecting next and previous links
// of neighboring verts past it. Decrement vertex count
vNext[vPrev[i]] = vNext[i] ;
vPrev[vNext[i]] = vPrev[i] ;
-- n ;
// Visit the previous vertex next
i = vPrev[i] ;
// Reset Count
nCount = n ;
}
else {
// Current vertex is not an ear; visit the next vertex
i = vNext[i] ;
}
}
// Last triangle is an ear
vTr.push_back( vPol[vPrev[i]]) ;
vTr.push_back( vPol[i]) ;
vTr.push_back( vPol[vNext[i]]) ;
return true ;
}
//----------------------------------------------------------------------------
// Triangulate the CCW n-gon specified by the vertices vPt (Pt[n] != Pt[0])
// Ear Clipping algorithm enhanced, choose smaller triangle aspect ratio
// AR = ( Lmax * Lmax) / ( 2 * Area) = SqLenMax / L1 * L2
//----------------------------------------------------------------------------
bool
Triangulate::MakeByEC3( const PNTVECTOR& vPt, const INTVECTOR& vPol, INTVECTOR& vTr)
{
// Clear triangle vector
vTr.clear() ;
// At least 3 points
int n = int( vPol.size()) ;
if ( n < 3)
return false ;
// Preallocate triangle vector ( #triangles = n - 2)
vTr.reserve( 3 * ( n - 2)) ;
// Set up previous and next links to effectively form a double-linked vertex list
INTVECTOR vPrev( n) ;
INTVECTOR vNext( n) ;
for ( int j = 0 ; j < n ; ++ j) {
vPrev[j] = j - 1 ;
vNext[j] = j + 1 ;
}
vPrev[0] = n - 1 ;
vNext[n-1] = 0 ;
// Prepare Ear status vector
INTVECTOR vEar( n, EAS_NULL) ;
// Prepare PointGrid
if ( ! PrepareGrid( vPt, vPol, vPrev, vNext))
return false ;
// Start at vertex 0
int i = 0 ;
int nCount = n ;
// Keep removing vertices until just a triangle left
while ( n >= 3) {
// To avoid infinite loop
if ( nCount <= 0)
return false ;
-- nCount ;
// Test if current vertex, v[i], is an ear
if ( vEar[i] == EAS_NULL)
vEar[i] = ( TestTriangle( vPt, vPol, vPrev, vNext, i) ? EAS_OK : EAS_NO) ;
bool bIsEar = ( vEar[i] == EAS_OK) ;
bool bSave = bIsEar ;
if ( bIsEar) {
// Square Length & Aspect Ratio
double dSqLen = SqDist(vPt[vPol[vPrev[i]]], vPt[vPol[vNext[i]]]) ;
double dAR = CalcTriangleAspectRatio( vPt[vPol[vPrev[i]]], vPt[vPol[i]], vPt[vPol[vNext[i]]]) ;
// Try with all other verticis
int ii = i ;
int j = vNext[i] ;
while ( j != ii) {
// New Square Length
double dNewSqLen = SqDist(vPt[vPol[vPrev[j]]], vPt[vPol[vNext[j]]]) ;
if ( dNewSqLen < 0.99 * dSqLen) {
// New Aspect Ratio
double dNewAR = CalcTriangleAspectRatio( vPt[vPol[vPrev[j]]], vPt[vPol[j]], vPt[vPol[vNext[j]]]) ;
// if better, test if triangle ok
if ( dNewAR < 30 || dNewAR < 1.2 * dAR) {
if ( vEar[j] == EAS_NULL)
vEar[j] = ( TestTriangle( vPt, vPol, vPrev, vNext, j) ? EAS_OK : EAS_NO) ;
if ( vEar[j] == EAS_OK) {
dSqLen = dNewSqLen ;
dAR = min( dAR, dNewAR) ;
i = j ;
}
}
}
j = vNext[j] ;
}
}
// Verify if triangle is null (accept to discard)
else {
if ( Collinear( vPt[vPol[vPrev[i]]], vPt[vPol[i]], vPt[vPol[vNext[i]]]) &&
! Aligned( vPt[vPol[vPrev[i]]], vPt[vPol[i]], vPt[vPol[vNext[i]]]))
bIsEar = true ;
}
// If current vertex v[i] is an ear, delete it and visit the previous vertex
if ( bIsEar) {
// Triangle (v[prev[i]], v[i], v[next[i]]) is an ear to save
if ( bSave) {
vTr.push_back( vPol[vPrev[i]]) ;
vTr.push_back( vPol[i]) ;
vTr.push_back( vPol[vNext[i]]) ;
}
// Reset earity of diagonal endpoints
vEar[vPrev[i]] = EAS_NULL ;
vEar[vNext[i]] = EAS_NULL ;
// Delete vertex v[i] by redirecting next and previous links
// of neighboring verts past it. Decrement vertex count
vNext[vPrev[i]] = vNext[i] ;
vPrev[vNext[i]] = vPrev[i] ;
-- n ;
// Visit the previous vertex next
i = vPrev[i] ;
// Reset Count
nCount = n ;
}
else {
// Current vertex is not an ear; visit the next vertex
i = vNext[i] ;
}
}
return true ;
}
@@ -260,15 +551,36 @@ Triangulate::TestTriangle( const PNTVECTOR& vPt, const INTVECTOR& vPol,
// An ear must be convex (here counterclockwise)
if ( TriangleIsCCW( vPt[vPol[vPrev[i]]], vPt[vPol[i]], vPt[vPol[vNext[i]]])) {
// Loop over all vertices not part of the tentative ear
int k = vNext[vNext[i]] ;
do {
// If vertex k is inside the ear triangle, then this is not an ear
if ( TestPointInTriangle( vPt[vPol[k]], vPt[vPol[vPrev[i]]], vPt[vPol[i]], vPt[vPol[vNext[i]]])) {
bIsEar = false ;
break ;
}
k = vNext[k] ;
} while (k != vPrev[i]) ;
BBox3d b3Tria ;
b3Tria.Add( vPt[vPol[vPrev[i]]]) ;
b3Tria.Add( vPt[vPol[i]]) ;
b3Tria.Add( vPt[vPol[vNext[i]]]) ;
m_VertGrid.Find( b3Tria, m_vVert) ;
for ( int j = 0 ; j < int( m_vVert.size()) ; ++ j) {
int k = m_vVert[j] ;
if ( k == i || k == vPrev[i] || k == vNext[i] )
continue ;
// If vertex k is on a triangle vertex
if ( AreSamePoint( vPt[vPol[k]], vPt[vPol[vPrev[i]]]) ||
AreSamePoint( vPt[vPol[k]], vPt[vPol[i]]) ||
AreSamePoint( vPt[vPol[k]], vPt[vPol[vNext[i]]])) {
// Test previous segment with triangle diagonal
if ( TestIntersection( vPt[vPol[vPrev[k]]], vPt[vPol[k]], vPt[vPol[vPrev[i]]], vPt[vPol[vNext[i]]])) {
bIsEar = false ;
break ;
}
// Test next segment with triangle diagonal
if ( TestIntersection( vPt[vPol[k]], vPt[vPol[vNext[k]]], vPt[vPol[vPrev[i]]], vPt[vPol[vNext[i]]])) {
bIsEar = false ;
break ;
}
}
// If vertex k is inside the ear triangle, then this is not an ear
else if ( TestPointInTriangle( vPt[vPol[k]], vPt[vPol[vPrev[i]]], vPt[vPol[i]], vPt[vPol[vNext[i]]])) {
bIsEar = false ;
break ;
}
}
}
else {
// The ear triangle is clockwise so v[i] is not an ear
@@ -279,36 +591,103 @@ Triangulate::TestTriangle( const PNTVECTOR& vPt, const INTVECTOR& vPol,
}
//----------------------------------------------------------------------------
// Ratio between max side and opposite height
double
Triangulate::CalcTriangleAspectRatio( const Point3d& ptPa, const Point3d& ptPb, const Point3d& ptPc)
{
double dSqDistA = SquareDist( ptPa, ptPb) ;
double dSqDistB = SquareDist( ptPb, ptPc) ;
double dSqDistC = SquareDist( ptPc, ptPa) ;
double dTwoArea = fabs( TwoArea( ptPa, ptPb, ptPc)) ;
if ( dTwoArea < EPS_SMALL * EPS_SMALL)
return INFINITO ;
else
return ( std::max( dSqDistA, std::max( dSqDistB, dSqDistC)) / dTwoArea) ;
}
//----------------------------------------------------------------------------
double
Triangulate::SquareDist( const Point3d& ptA, const Point3d& ptB)
{
switch ( m_nPlane) {
default : // PL_XY
return (( ptB.x - ptA.x) * ( ptB.x - ptA.x) + ( ptB.y - ptA.y) * ( ptB.y - ptA.y)) ;
case PL_YZ :
return (( ptB.y - ptA.y) * ( ptB.y - ptA.y) + ( ptB.z - ptA.z) * ( ptB.z - ptA.z)) ;
case PL_ZX :
return (( ptB.z - ptA.z) * ( ptB.z - ptA.z) + ( ptB.x - ptA.x) * ( ptB.x - ptA.x)) ;
}
}
//----------------------------------------------------------------------------
// Vector product is double of the area (positive if CCW)
double
Triangulate::TwoArea( const Point3d& ptA, const Point3d& ptB, const Point3d& ptC)
{
switch ( m_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) ;
}
}
//----------------------------------------------------------------------------
// Distance less than tolerance
bool
Triangulate::AreSamePoint( const Point3d& ptA, const Point3d& ptB, double dToler)
{
return ( SquareDist( ptA, ptB) < dToler * dToler) ;
}
//----------------------------------------------------------------------------
// Collinear <--> Null Area
bool
Triangulate::Aligned( const Point3d& ptA, const Point3d& ptB, const Point3d& ptC)
{
switch ( m_nPlane) {
default : // PL_XY
return (( ptB.x - ptA.x) * ( ptC.x - ptB.x) + ( ptB.y - ptA.y) * ( ptC.y - ptB.y)) > 0 ;
case PL_YZ :
return (( ptB.y - ptA.y) * ( ptC.y - ptB.y) + ( ptB.z - ptA.z) * ( ptC.z - ptB.z)) > 0 ;
case PL_ZX :
return (( ptB.z - ptA.z) * ( ptC.z - ptB.z) + ( ptB.x - ptA.x) * ( ptC.x - ptB.x)) > 0 ;
}
}
//----------------------------------------------------------------------------
// Collinear <--> Null Area
bool
Triangulate::Collinear( const Point3d& ptA, const Point3d& ptB, const Point3d& ptC, double dToler)
{
return ( fabs( TwoArea( ptA, ptB, ptC)) < dToler * dToler) ;
}
//----------------------------------------------------------------------------
// Positive Area means A -> B -> C counterclockwise
bool
Triangulate::TriangleIsCCW( const Point3d& ptA, const Point3d& ptB, const Point3d& ptC, double dToler)
{
double dV11 ;
double dV12 ;
double dV21 ;
double dV22 ;
return ( TwoArea( ptA, ptB, ptC) > dToler * dToler) ;
}
switch ( m_nPlane) {
default : // PL_XY
dV11 = ptB.x - ptA.x ;
dV12 = ptB.y - ptA.y ;
dV21 = ptC.x - ptB.x ;
dV22 = ptC.y - ptB.y ;
break ;
case PL_YZ :
dV11 = ptB.y - ptA.y ;
dV12 = ptB.z - ptA.z ;
dV21 = ptC.y - ptB.y ;
dV22 = ptC.z - ptB.z ;
break ;
case PL_ZX :
dV11 = ptB.z - ptA.z ;
dV12 = ptB.x - ptA.x ;
dV21 = ptC.z - ptB.z ;
dV22 = ptC.x - ptB.x ;
break ;
}
return ( ( dV11 * dV22 - dV12 * dV21) > dToler * dToler) ;
//----------------------------------------------------------------------------
// Proper intersection between line segments
bool
Triangulate::TestIntersection( const Point3d& ptA1, const Point3d& ptA2,
const Point3d& ptB1, const Point3d& ptB2)
{
// Collinearity is not considered intersection
if ( Collinear( ptA1, ptA2, ptB1) ||
Collinear( ptA1, ptA2, ptB2) ||
Collinear( ptB1, ptB2, ptA1) ||
Collinear( ptB1, ptB2, ptA2))
return false ;
// To intersect, the endpoints of a line segment must be on opposite side of the other line segment
return ( TriangleIsCCW( ptA1, ptA2, ptB1) != TriangleIsCCW( ptA1, ptA2, ptB2) &&
TriangleIsCCW( ptB1, ptB2, ptA1) != TriangleIsCCW( ptB1, ptB2, ptA2)) ;
}
//----------------------------------------------------------------------------
@@ -316,20 +695,279 @@ Triangulate::TriangleIsCCW( const Point3d& ptA, const Point3d& ptB, const Point3
bool
Triangulate::TestPointInTriangle( const Point3d& ptP, const Point3d& ptA, const Point3d& ptB, const Point3d& ptC)
{
// if P is on a vertex is considered outside
if ( AreSamePointApprox( ptP, ptA))
// If P is on a vertex is considered outside
if ( AreSamePoint( ptP, ptA))
return false ;
if ( AreSamePointApprox( ptP, ptB))
if ( AreSamePoint( ptP, ptB))
return false ;
if ( AreSamePointApprox( ptP, ptC))
if ( AreSamePoint( ptP, ptC))
return false ;
// if P is on the right of at least one edge is outside
// If P is on the right of at least one edge is outside
if ( TriangleIsCCW( ptA, ptP, ptB))
return false ;
if ( TriangleIsCCW( ptB, ptP, ptC))
return false ;
if ( TriangleIsCCW( ptC, ptP, ptA))
return false ;
// P is in triangle
return true ;
}
//----------------------------------------------------------------------------
bool
Triangulate::SortInternalLoops( const POLYLINEVECTOR& vPL, INTVECTOR& vOrd)
{
// riempio vettore con indice e massimo specifico per ogni loop interno
typedef std::pair<int,double> INDMAX ; // coppia indice, massimo
typedef std::vector<INDMAX> INDMAXVECTOR ; // vettore di coppie indice, massimo
INDMAXVECTOR vMax ;
vMax.reserve( vPL.size()) ;
vMax.emplace_back( 0, 0.0) ;
for ( int i = 1 ; i < int( vPL.size()) ; ++ i) {
BBox3d b3Loc ;
vPL[i].GetLocalBBox( b3Loc) ;
switch ( m_nPlane) {
default : // PL_XY
vMax.emplace_back( i, b3Loc.GetMax().x) ;
break ;
case PL_YZ :
vMax.emplace_back( i, b3Loc.GetMax().y) ;
break ;
case PL_ZX :
vMax.emplace_back( i, b3Loc.GetMax().z) ;
break ;
}
}
// ordino vettore in senso decrescente rispetto al massimo
sort( vMax.begin() + 1, vMax.end(),
[]( const INDMAX& a, const INDMAX&b) { return a.second > b.second ; }) ;
// copio indice nel vettore di ordine
vOrd.reserve( vPL.size()) ;
for ( int i = 0 ; i < int( vPL.size()) ; ++ i)
vOrd.push_back( vMax[i].first) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Triangulate::GetPntVectorFromPolyline( const PolyLine& PL, bool bXmaxStart, PNTVECTOR& vPi)
{
// copio i punti nel vettore (tranne il primo che coincide con l'ultimo)
Point3d ptP ;
if ( ! PL.GetFirstPoint( ptP))
return false ;
while ( PL.GetNextPoint( ptP)) {
vPi.push_back( ptP) ;
}
// se non richiesto riordino per Xmax o Ymax o Zmax, ho finito
if ( ! bXmaxStart)
return true ;
// determino l'indice del punto con Xmax
int nI = - 1 ;
double dXmax = - INFINITO ;
for ( int i = 0 ; i < int( vPi.size()) ; ++ i) {
switch ( m_nPlane) {
default : // PL_XY
if ( vPi[i].x > dXmax) {
dXmax = vPi[i].x ;
nI = i ;
}
break ;
case PL_YZ :
if ( vPi[i].y > dXmax) {
dXmax = vPi[i].y ;
nI = i ;
}
break ;
case PL_ZX :
if ( vPi[i].z > dXmax) {
dXmax = vPi[i].z ;
nI = i ;
}
break ;
}
}
if ( nI == - 1)
return false ;
// riordino il vettore, per avere il punto con Xmax in prima posizione
return ChangeStartPntVector( nI, vPi) ;
}
//----------------------------------------------------------------------------
bool
Triangulate::GetOuterPntToJoin( const PNTVECTOR& vPt, const Point3d& ptP, int& nI)
{
// cerco prima intersezione del raggio dal punto con direzione X+ al contorno esterno
nI = - 1 ;
double dMinDist = INFINITO ;
Point3d ptInt ;
int nNumPt = int( vPt.size()) ;
for ( int i = 0 ; i < nNumPt ; ++ i) {
// indice punto precedente
int h = ( i - 1 >= 0 ) ? i - 1 : nNumPt - 1 ;
// indice punto successivo
int j = ( i + 1 < nNumPt) ? i + 1 : 0 ;
// mi metto nel piano principale
switch (m_nPlane) {
default : // PL_XY
// se punto esattamente sul raggio e raggio interno al settore
if ( vPt[i].x > ptP.x && fabs( vPt[i].y - ptP.y) < EPS_SMALL &&
PointInSector( ptP, vPt[h], vPt[i], vPt[j])) {
// se distanza minore della minima, nuovo minimo
if ( ( vPt[i].x - ptP.x) < dMinDist) {
dMinDist = vPt[i].x - ptP.x ;
nI = i ;
ptInt = vPt[i] ;
}
}
// se segmento al punto successivo che attraversa il raggio e raggio interno ovvero a sinistra ( segmento crescente in Y)
else if ( vPt[i].y < ptP.y && vPt[j].y > ptP.y) {
// calcolo l'ascissa di intersezione
double dCoeff = ( ptP.y - vPt[i].y) / ( vPt[j].y - vPt[i].y) ;
double dX = vPt[i].x + ( vPt[j].x - vPt[i].x) * dCoeff ;
// se sta sul raggio e distanza minore della minima
if ( dX > ptP.x && ( dX - ptP.x) < dMinDist) {
dMinDist = dX - ptP.x ;
nI = ( vPt[i].x >= vPt[j].x) ? i : j ;
double dZ = vPt[i].z + ( vPt[j].z - vPt[i].z) * dCoeff ;
ptInt.Set( dX, ptP.y, dZ) ;
}
}
break ;
case PL_YZ :
// se punto esattamente sul raggio e raggio interno al settore
if ( vPt[i].y > ptP.y && fabs( vPt[i].z - ptP.z) < EPS_SMALL &&
PointInSector( ptP, vPt[h], vPt[i], vPt[j])) {
// se distanza minore della minima, nuovo minimo
if ( ( vPt[i].y - ptP.y) < dMinDist) {
dMinDist = vPt[i].y - ptP.y ;
nI = i ;
ptInt = vPt[i] ;
}
}
// se segmento al punto successivo che attraversa il raggio e raggio interno ovvero a sinistra ( segmento crescente in Y)
else if ( vPt[i].z < ptP.z && vPt[j].z > ptP.z) {
// calcolo l'ascissa di intersezione
double dCoeff = ( ptP.z - vPt[i].z) / ( vPt[j].z - vPt[i].z) ;
double dY = vPt[i].y + ( vPt[j].y - vPt[i].y) * dCoeff ;
// se sta sul raggio e distanza minore della minima
if ( dY > ptP.y && ( dY - ptP.y) < dMinDist) {
dMinDist = dY - ptP.y ;
nI = ( vPt[i].y >= vPt[j].y) ? i : j ;
double dX = vPt[i].x + ( vPt[j].x - vPt[i].x) * dCoeff ;
ptInt.Set( dX, dY, ptP.z) ;
}
}
break ;
case PL_ZX :
// se punto esattamente sul raggio e raggio interno al settore
if ( vPt[i].z > ptP.z && fabs( vPt[i].x - ptP.x) < EPS_SMALL &&
PointInSector( ptP, vPt[h], vPt[i], vPt[j])) {
// se distanza minore della minima, nuovo minimo
if ( ( vPt[i].z - ptP.z) < dMinDist) {
dMinDist = vPt[i].z - ptP.z ;
nI = i ;
ptInt = vPt[i] ;
}
}
// se segmento al punto successivo che attraversa il raggio e raggio interno ovvero a sinistra ( segmento crescente in Y)
else if ( vPt[i].x < ptP.x && vPt[j].x > ptP.x) {
// calcolo l'ascissa di intersezione
double dCoeff = ( ptP.x - vPt[i].x) / ( vPt[j].x - vPt[i].x) ;
double dZ = vPt[i].z + ( vPt[j].z - vPt[i].z) * dCoeff ;
// se sta sul raggio e distanza minore della minima
if ( dZ > ptP.z && ( dZ - ptP.z) < dMinDist) {
dMinDist = dZ - ptP.z ;
nI = ( vPt[i].z >= vPt[j].z) ? i : j ;
double dY = vPt[i].y + ( vPt[j].y - vPt[i].y) * dCoeff ;
ptInt.Set( ptP.y, dY, dZ) ;
}
}
break ;
}
}
// non ho trovato alcunché, errore
if ( nI == - 1)
return false ;
// se ho trovato un punto esatto del contorno, non devo fare altri controlli
if ( AreSamePointApprox( ptInt, vPt[nI]))
return true ;
// devo ora verificare che il segmento che unisce i punti non intersechi altri lati del contorno esterno
// altrimenti tengo il punto con raggio più vicino a X_AX o Y_AX o Z_AX secondo m_nPlane
int nJ = nI ;
Point3d ptPa = ptP ;
Point3d ptPb = vPt[nI] ;
Point3d ptPc = ptInt ;
bool bSwap = false ;
switch ( m_nPlane) {
default : /* PL_XY */ bSwap = ( ptPb.y > ptPc.y) ; break ;
case PL_YZ : bSwap = ( ptPb.z > ptPc.z) ; break ;
case PL_ZX : bSwap = ( ptPb.x > ptPc.x) ; break ;
}
if ( bSwap)
swap( ptPb, ptPc) ;
double dMinTan = INFINITO ;
double dMinSqDist = INFINITO * INFINITO ;
for ( int i = 0 ; i < nNumPt ; ++ i) {
// salto il punto già trovato
if ( i == nJ)
continue ;
// verifico se sta nel triangolo
if ( TestPointInTriangle( vPt[i], ptPa, ptPb, ptPc)) {
double dTan = INFINITO ;
switch ( m_nPlane) {
default : /* PL_XY */ dTan = fabs(vPt[i].y - ptP.y) / (vPt[i].x - ptP.x) ; break ;
case PL_YZ : dTan = fabs(vPt[i].z - ptP.z) / (vPt[i].y - ptP.y) ; break ;
case PL_ZX : dTan = fabs(vPt[i].x - ptP.x) / (vPt[i].z - ptP.z) ; break ;
}
if ( dTan < dMinTan + EPS_ZERO) {
// indice punto precedente
int h = ( i - 1 >= 0) ? i - 1 : nNumPt - 1 ;
// indice punto successivo
int j = ( i + 1 < nNumPt) ? i + 1 : 0 ;
// verifico che il raggio che unisce i punti stia nel settore
if ( PointInSector( ptP, vPt[h], vPt[i], vPt[j])) {
double dSqDist = SqDist( vPt[i], ptP) ;
if ( dTan < dMinTan - EPS_ZERO || dSqDist < dMinSqDist) {
dMinTan = dTan ;
dMinSqDist = dSqDist ;
nI = i ;
}
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Triangulate::PointInSector( const Point3d& ptTest, const Point3d& ptPrev, const Point3d& ptCorn, const Point3d& ptNext)
{
// la parte valida del settore è a sinistra dei segmenti ptPrev --> ptCorn --> ptNext
// se corner convesso
if ( TriangleIsCCW( ptPrev, ptCorn, ptNext, 0))
return ( TriangleIsCCW( ptPrev, ptCorn, ptTest) &&
TriangleIsCCW( ptTest, ptCorn, ptNext)) ;
// altrimenti corner concavo ( reflex)
else
return ! ( TriangleIsCCW( ptTest, ptCorn, ptPrev, 0) &&
TriangleIsCCW( ptNext, ptCorn, ptTest, 0)) ;
}
//----------------------------------------------------------------------------
bool
ChangeStartPntVector( int nNewStart, PNTVECTOR& vPi)
{
// se il nuovo inizio coincide col vecchio, non devo fare alcunché
if ( nNewStart == 0)
return true ;
// se il nuovo indice è oltre la dimensione del vettore, errore
if ( nNewStart >= int( vPi.size()))
return false ;
// ciclo di aggiustamento
rotate( vPi.begin(), vPi.begin() + nNewStart, vPi.end()) ;
return true ;
}
+20 -6
View File
@@ -12,27 +12,41 @@
//----------------------------------------------------------------------------
#pragma once
#include "/EgtDev/Include/EGkGeoCollection.h"
class PolyLine ;
//----------------------------------------------------------------------------
enum { PL_XY = 1, PL_YZ = 2, PL_ZX = 3} ;
#include "/EgtDev/Include/EGkPolyLine.h"
#include "\EgtDev\Include\EGkPointGrid3d.h"
//----------------------------------------------------------------------------
class Triangulate
{
public :
bool Make( const PolyLine& PL, PNTVECTOR& vPt, INTVECTOR& vTr) ;
bool Make( const POLYLINEVECTOR& vPL, PNTVECTOR& vPt, INTVECTOR& vTr) ;
private :
bool PrepareGrid( const PNTVECTOR& vPt, const INTVECTOR& vPol,
const INTVECTOR& vPrev, const INTVECTOR& vNext) ;
bool MakeByEC( const PNTVECTOR& vPt, const INTVECTOR& vPol, INTVECTOR& vTr) ;
bool MakeByEC2( const PNTVECTOR& vPt, const INTVECTOR& vPol, INTVECTOR& vTr) ;
bool MakeByEC3( const PNTVECTOR& vPt, const INTVECTOR& vPol, INTVECTOR& vTr) ;
bool TestTriangle( const PNTVECTOR& vPt, const INTVECTOR& vPol,
const INTVECTOR& vPrev, INTVECTOR& vNext, int i) ;
double CalcTriangleAspectRatio( const Point3d& ptPa, const Point3d& ptPb, const Point3d& ptPc) ;
double SquareDist( const Point3d& ptA, const Point3d& ptB) ;
double TwoArea( const Point3d& ptA, const Point3d& ptB, const Point3d& ptC) ;
bool AreSamePoint( const Point3d& ptA, const Point3d& ptB, double dToler = EPS_SMALL) ;
bool Aligned( const Point3d& ptA, const Point3d& ptB, const Point3d& ptC) ;
bool Collinear( const Point3d& ptA, const Point3d& ptB, const Point3d& ptC, double dToler = EPS_SMALL) ;
bool TriangleIsCCW( const Point3d& ptA, const Point3d& ptB, const Point3d& ptC, double dToler = EPS_SMALL) ;
bool TestIntersection( const Point3d& ptA1, const Point3d& ptA2, const Point3d& ptB1, const Point3d& ptB2) ;
bool TestPointInTriangle( const Point3d& ptP, const Point3d& ptA, const Point3d& ptB, const Point3d& ptC) ;
bool SortInternalLoops( const POLYLINEVECTOR& vPL, INTVECTOR& vOrd) ;
bool GetPntVectorFromPolyline( const PolyLine& PL, bool bXmaxStart, PNTVECTOR& vPi) ;
bool GetOuterPntToJoin( const PNTVECTOR& vPt, const Point3d& ptP, int& nI) ;
bool PointInSector( const Point3d& ptTest, const Point3d& ptPrev, const Point3d& ptCorn, const Point3d& ptNext) ;
private :
int m_nPlane ;
} ;
PointGrid3d m_VertGrid ;
INTVECTOR m_vVert ;
} ;