EgtGeomKernel 1.6b3 :
- aggiunta gestione buchi alle triangolazione di poligoni - creazione suerfici trimesh da regioni con buchi.
This commit is contained in:
+4
-4
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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) ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "/EgtDev/Include/EGkCurve.h"
|
||||
#include "/EgtDev/Include/EGnStringBase.h"
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
#include <WinGDI.h>
|
||||
|
||||
|
||||
+6
-6
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 ;
|
||||
} ;
|
||||
|
||||
Reference in New Issue
Block a user