From ebd6b8b4a5cab74d58a817bbd04cac42aed5c186 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Tue, 6 May 2014 07:45:56 +0000 Subject: [PATCH] EgtGeomKernel 1.5e2 : - creazione STM per rototraslazione e da due curve. --- EgtGeomKernel.rc | Bin 11710 -> 11710 bytes GdbExecutor.cpp | 245 ++++++++++++----------- GdbExecutor.h | 4 + PolyLine.cpp | 10 +- SurfTriMesh.cpp | 500 +++++++++++++++++++++++++++++++++++------------ SurfTriMesh.h | 8 +- 6 files changed, 526 insertions(+), 241 deletions(-) diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 78eef9f6b9eb968b71c9eeedcccddb173a3ead68..efacc53409690714dde8b138ba21d1998d0baead 100644 GIT binary patch delta 81 zcmdlNy)SyhH#SD2&FAG5nSsGetGeoObj( nIdCrv)) ; - if ( pCrv == nullptr) - return false ; - // recupero il riferimento della curva - Frame3d frCrv ; - if ( ! m_pGDB->GetGlobFrame( nIdCrv, frCrv)) - return false ; // recupero il riferimento del gruppo destinazione Frame3d frDest ; if ( ! m_pGDB->GetGroupGlobFrame( GetIdParam( vsParams[1]), frDest)) return false ; // calcolo la polilinea che approssima la curva PolyLine PL ; - // se i riferimenti sono uguali - if ( AreSameFrame( frCrv, frDest)) { - // ricavo l'approssimazione - if ( ! pCrv->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL)) - return false ; - } - // altrimenti devo prima trasformare la curva - else { - // creo una copia della curva (da buttare alla fine) - PtrOwner pModCrv( GetCurve( pCrv->Clone())) ; - if ( ! IsValid( pModCrv)) - return false ; - // eseguo la trasformazione - pModCrv->ToGlob( frCrv) ; - pModCrv->ToLoc( frDest) ; - // ricavo l'approssimazione - if ( ! pModCrv->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL)) - return false ; - } + if ( ! GetPolylineFromCurve( nIdCrv, frDest, dLinTol, PL)) + return false ; // creo la superficie PtrOwner pSTM( CreateSurfTriMesh()) ; if ( ! IsValid( pSTM)) return false ; // costruisco la triangolazione - if ( ! pSTM->CreateByTriangulation( PL)) + if ( ! pSTM->CreateByFlatContour( PL)) return false ; // inserisco la superficie trimesh nel DB return AddGeoObj( vsParams[0], vsParams[1], Release( pSTM)) ; @@ -912,38 +888,14 @@ GdbExecutor::ExecuteSurfTriMesh( const string& sCmd2, const STRVECTOR& vsParams) FromString( vsParams[4], dLinTol) ; // recupero la curva int nIdCrv = GetIdParam( vsParams[2]) ; - const ICurve* pCrv = GetCurve( m_pGDB->GetGeoObj( nIdCrv)) ; - if ( pCrv == nullptr) - return false ; - // recupero il riferimento della curva - Frame3d frCrv ; - if ( ! m_pGDB->GetGlobFrame( nIdCrv, frCrv)) - return false ; // recupero il riferimento del gruppo destinazione Frame3d frDest ; if ( ! m_pGDB->GetGroupGlobFrame( GetIdParam( vsParams[1]), frDest)) return false ; // calcolo la polilinea che approssima la curva PolyLine PL ; - // se i riferimenti sono uguali - if ( AreSameFrame( frCrv, frDest)) { - // ricavo l'approssimazione - if ( ! pCrv->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL)) - return false ; - } - // altrimenti devo prima trasformare la curva - else { - // creo una copia della curva (da buttare alla fine) - PtrOwner pModCrv( GetCurve( pCrv->Clone())) ; - if ( ! IsValid( pModCrv)) - return false ; - // eseguo la trasformazione - pModCrv->ToGlob( frCrv) ; - pModCrv->ToLoc( frDest) ; - // ricavo l'approssimazione - if ( ! pModCrv->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL)) - return false ; - } + if ( ! GetPolylineFromCurve( nIdCrv, frDest, dLinTol, PL)) + return false ; // recupero il vettore di estrusione Vector3d vtExtr ; if ( ! GetVectorParam( vsParams[3], vtExtr)) @@ -958,81 +910,156 @@ GdbExecutor::ExecuteSurfTriMesh( const string& sCmd2, const STRVECTOR& vsParams) // inserisco la superficie trimesh nel DB return AddGeoObj( vsParams[0], vsParams[1], Release( pSTM)) ; } - // se creazione per rivoluzione - else if ( sCmd2 == "REV" || sCmd2 == "BYREVOLUTION") { - // 6 o 7 parametri : Id, ParentId, IdCurve, ptRev, vtRev, dAngRot[, dLinTol] - if ( vsParams.size() != 6 && vsParams.size() != 7) + // se creazione da 2 percorsi + else if ( sCmd2 == "2P" || sCmd2 == "BY2PATHS") { + // 4 o 5 parametri : Id, ParentId, IdCurve1, IdCurve2[, dLinTol] + if ( vsParams.size() != 4 && vsParams.size() != 5) return false ; // recupero la tolleranza lineare double dLinTol = LIN_TOL_STD ; - if ( vsParams.size() == 7) - FromString( vsParams[6], dLinTol) ; - // recupero la curva - int nIdCrv = GetIdParam( vsParams[2]) ; - const ICurve* pCrv = GetCurve( m_pGDB->GetGeoObj( nIdCrv)) ; - if ( pCrv == nullptr) - return false ; - // recupero il riferimento della curva - Frame3d frCrv ; - if ( ! m_pGDB->GetGlobFrame( nIdCrv, frCrv)) - return false ; + if ( vsParams.size() == 5) + FromString( vsParams[4], dLinTol) ; // recupero il riferimento del gruppo destinazione Frame3d frDest ; if ( ! m_pGDB->GetGroupGlobFrame( GetIdParam( vsParams[1]), frDest)) return false ; - // calcolo la polilinea che approssima la curva - PolyLine PL ; - // se i riferimenti sono uguali - if ( AreSameFrame( frCrv, frDest)) { - // ricavo l'approssimazione - if ( ! pCrv->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL)) - return false ; - } - // altrimenti devo prima trasformare la curva - else { - // creo una copia della curva (da buttare alla fine) - PtrOwner pModCrv( GetCurve( pCrv->Clone())) ; - if ( ! IsValid( pModCrv)) - return false ; - // eseguo la trasformazione - pModCrv->ToGlob( frCrv) ; - pModCrv->ToLoc( frDest) ; - // ricavo l'approssimazione - if ( ! pModCrv->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL)) - return false ; - } - // recupero il punto dell'asse di rivoluzione - Point3d ptAx ; - if ( ! GetPointParam( vsParams[3], ptAx)) + // recupero l'identificativo della prima curva + int nIdCrv1 = GetIdParam( vsParams[2]) ; + // calcolo la polilinea che approssima la prima curva + PolyLine PL1 ; + if ( ! GetPolylineFromCurve( nIdCrv1, frDest, dLinTol, PL1)) return false ; - // recupero il vettore dell'asse di rivoluzione - Vector3d vtAx ; - if ( ! GetVectorParam( vsParams[4], vtAx)) + // recupero l'identificativo della seconda curva + int nIdCrv2 = GetIdParam( vsParams[3]) ; + // calcolo la polilinea che approssima la seconda curva + PolyLine PL2 ; + if ( ! GetPolylineFromCurve( nIdCrv2, frDest, dLinTol, PL2)) return false ; - // recupero l'angolo di rotazione - double dAngRotDeg ; - if ( ! FromString( vsParams[5], dAngRotDeg)) - return false ; - // calcolo lo step di rotazione - double dMaxRad = 0 ; - PL.GetMaxDistanceFromLine( dMaxRad, ptAx, vtAx, 1, false) ; - if ( dMaxRad < EPS_SMALL) - return false ; - double dStepRotDeg = sqrt( 8 * dLinTol / dMaxRad) * RADTODEG ; // creo la superficie PtrOwner pSTM( CreateSurfTriMesh()) ; if ( ! IsValid( pSTM)) return false ; - // costruisco la rivoluzione - if ( ! pSTM->CreateByRevolution( PL, ptAx, vtAx, dAngRotDeg, dStepRotDeg)) + // costruisco la rigata tra le due curve + if ( ! pSTM->CreateByTwoCurves( PL1, PL2)) return false ; // inserisco la superficie trimesh nel DB return AddGeoObj( vsParams[0], vsParams[1], Release( pSTM)) ; } + // se creazione per rivoluzione + else if ( sCmd2 == "REV" || sCmd2 == "BYREVOLUTION") { + return SurfTriMeshByScrewing( false, vsParams) ; + } + // se creazione per rotoavvitamento + else if ( sCmd2 == "SCR" || sCmd2 == "BYSCREWING") { + return SurfTriMeshByScrewing( true, vsParams) ; + } else return false ; } +//---------------------------------------------------------------------------- +bool +GdbExecutor::SurfTriMeshByScrewing( bool bMove, const STRVECTOR& vsParams) +{ + // default per tolleranza lineare e movimento lungo l'asse + double dLinTol = LIN_TOL_STD ; + double dMove = 0 ; + // se previsto movimento + if ( bMove) { + // 7 o 8 parametri : Id, ParentId, IdCurve, ptRev, vtRev, dAngRot, dMove[, dLinTol] + if ( vsParams.size() != 7 && vsParams.size() != 8) + return false ; + // recupero la tolleranza lineare + if ( vsParams.size() == 8) + FromString( vsParams[7], dLinTol) ; + // recupero il movimento lungo l'asse + if ( ! FromString( vsParams[6], dMove)) + return false ; + } + // altrimenti con sola rotazione + else { + // 6 o 7 parametri : Id, ParentId, IdCurve, ptRev, vtRev, dAngRot[, dLinTol] + if ( vsParams.size() != 6 && vsParams.size() != 7) + return false ; + // recupero la tolleranza lineare + if ( vsParams.size() == 7) + FromString( vsParams[6], dLinTol) ; + // non c'é movimento lungo l'asse + } + // recupero l'identificativo della curva + int nIdCrv = GetIdParam( vsParams[2]) ; + // recupero il riferimento del gruppo destinazione + Frame3d frDest ; + if ( ! m_pGDB->GetGroupGlobFrame( GetIdParam( vsParams[1]), frDest)) + return false ; + // calcolo la polilinea che approssima la curva + PolyLine PL ; + if ( ! GetPolylineFromCurve( nIdCrv, frDest, dLinTol, PL)) + return false ; + // recupero il punto dell'asse di rivoluzione + Point3d ptAx ; + if ( ! GetPointParam( vsParams[3], ptAx)) + return false ; + // recupero il vettore dell'asse di rivoluzione + Vector3d vtAx ; + if ( ! GetVectorParam( vsParams[4], vtAx)) + return false ; + // recupero l'angolo di rotazione + double dAngRotDeg ; + if ( ! FromString( vsParams[5], dAngRotDeg)) + return false ; + // calcolo lo step di rotazione + double dMaxRad = 0 ; + PL.GetMaxDistanceFromLine( dMaxRad, ptAx, vtAx, 1, false) ; + if ( dMaxRad < EPS_SMALL) + return false ; + double dStepRotDeg = sqrt( 8 * dLinTol / dMaxRad) * RADTODEG ; + // creo la superficie + PtrOwner pSTM( CreateSurfTriMesh()) ; + if ( ! IsValid( pSTM)) + return false ; + // costruisco la rivoluzione + if ( ! pSTM->CreateByScrewing( PL, ptAx, vtAx, dAngRotDeg, dStepRotDeg, dMove)) + return false ; + // inserisco la superficie trimesh nel DB + return AddGeoObj( vsParams[0], vsParams[1], Release( pSTM)) ; +} + +//---------------------------------------------------------------------------- +bool +GdbExecutor::GetPolylineFromCurve( int nId, const Frame3d& frDest, double dLinTol, PolyLine& PL) +{ + // recupero la curva + const ICurve* pCrv = GetCurve( m_pGDB->GetGeoObj( nId)) ; + if ( pCrv == nullptr) + return false ; + // recupero il riferimento della curva + Frame3d frCrv ; + if ( ! m_pGDB->GetGlobFrame( nId, frCrv)) + return false ; + // calcolo la polilinea che approssima la curva + // se i riferimenti sono uguali + if ( AreSameFrame( frCrv, frDest)) { + // ricavo l'approssimazione + if ( ! pCrv->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL)) + return false ; + } + // altrimenti devo prima trasformare la curva + else { + // creo una copia della curva (da buttare alla fine) + PtrOwner pModCrv( GetCurve( pCrv->Clone())) ; + if ( ! IsValid( pModCrv)) + return false ; + // eseguo la trasformazione + pModCrv->ToGlob( frCrv) ; + pModCrv->ToLoc( frDest) ; + // ricavo l'approssimazione + if ( ! pModCrv->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL)) + return false ; + } + return true ; +} + //---------------------------------------------------------------------------- bool GdbExecutor::AddGeoObj( const string& sId, const string& sIdParent, IGeoObj* pGeoObj) diff --git a/GdbExecutor.h b/GdbExecutor.h index 5dbe2ae..e6b66bf 100644 --- a/GdbExecutor.h +++ b/GdbExecutor.h @@ -19,6 +19,8 @@ #include "/EgtDev/Include/EgtExecMgr.h" #include "/EgtDev/Include/EgtNumCollection.h" +class PolyLine ; + //---------------------------------------------------------------------------- class GdbExecutor : public IGdbExecutor { @@ -43,6 +45,7 @@ class GdbExecutor : public IGdbExecutor bool GetPointWParam( const std::string& sParam, Point3d& ptP, double& dW) ; bool GetFrameParam( const std::string& sParam, Frame3d& frF) ; bool GetColorParam( const std::string& sParam, bool& bByParent, Color& cCol) ; + bool GetPolylineFromCurve( int nId, const Frame3d& frDest, double dLinTol, PolyLine& PL) ; bool ExecuteGroup( const std::string& sCmd2, const STRVECTOR& vsParams) ; bool ExecutePoint( const std::string& sCmd2, const STRVECTOR& vsParams) ; bool ExecuteVector( const std::string& sCmd2, const STRVECTOR& vsParams) ; @@ -55,6 +58,7 @@ class GdbExecutor : public IGdbExecutor bool CurveCompoFromSplit( const STRVECTOR& vsParams) ; bool CurveCompoAddCurve( const STRVECTOR& vsParams) ; bool ExecuteSurfTriMesh( const std::string& sCmd2, const STRVECTOR& vsParams) ; + bool SurfTriMeshByScrewing( bool bMove, const STRVECTOR& vsParams) ; bool ExecuteLevel( const std::string& sCmd2, const STRVECTOR& vsParams) ; bool ExecuteMode( const std::string& sCmd2, const STRVECTOR& vsParams) ; bool ExecuteStatus( const std::string& sCmd2, const STRVECTOR& vsParams) ; diff --git a/PolyLine.cpp b/PolyLine.cpp index 0ec53a1..6ee20f4 100644 --- a/PolyLine.cpp +++ b/PolyLine.cpp @@ -110,7 +110,7 @@ PolyLine::Splice( PolyLine& PL) bool PolyLine::IsClosed( void) const { - if ( m_lUPoints.empty()) + if ( m_lUPoints.size() < 3) return false ; return ( AreSamePointNear( m_lUPoints.front().second, m_lUPoints.back().second)) ; @@ -134,11 +134,13 @@ PolyLine::GetFirstUPoint( double* pdPar, Point3d* pptP) const //---------------------------------------------------------------------------- bool -PolyLine::GetNextUPoint( double* pdPar, Point3d* pptP) const +PolyLine::GetNextUPoint( double* pdPar, Point3d* pptP, bool bNotLast) const { ++ m_iter ; if ( m_iter == m_lUPoints.end()) return false ; + if ( bNotLast && m_iter == -- ( m_lUPoints.end())) + return false ; if ( pdPar != nullptr) *pdPar = m_iter->first ; @@ -170,11 +172,13 @@ PolyLine::GetLastUPoint( double* pdPar, Point3d* pptP) const //---------------------------------------------------------------------------- bool -PolyLine::GetPrevUPoint( double* pdPar, Point3d* pptP) const +PolyLine::GetPrevUPoint( double* pdPar, Point3d* pptP, bool bNotFirst) const { if ( m_iter == m_lUPoints.begin()) return false ; -- m_iter ; + if ( bNotFirst && m_iter == m_lUPoints.begin()) + return false ; if ( pdPar != nullptr) *pdPar = m_iter->first ; diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index 9f55e04..24bdb37 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -749,7 +749,7 @@ SurfTriMesh::AdjustTopology( void) //---------------------------------------------------------------------------- bool -SurfTriMesh::CreateByTriangulation( const PolyLine& PL) +SurfTriMesh::CreateByFlatContour( const PolyLine& PL) { // eseguo la triangolazione PNTVECTOR vPnt ; @@ -788,10 +788,14 @@ SurfTriMesh::CreateByTriangulation( const PolyLine& PL) bool SurfTriMesh::CreateByExtrusion( const PolyLine& PL, const Vector3d& vtExtr) { - // verifico che il vettore di estrusione sia non nullo + // il vettore di estrusione deve essere non nullo if ( vtExtr.IsSmall()) return false ; + // la polilinea deve avere almeno 2 punti + if ( PL.GetPointNbr() < 2) + return false ; + // verifico se la polilinea è chiusa bool bClosed = PL.IsClosed() ; @@ -801,44 +805,201 @@ SurfTriMesh::CreateByExtrusion( const PolyLine& PL, const Vector3d& vtExtr) return false ; // inserisco il primo vertice della polilinea e il suo estruso - int nP = 0 ; int nV = -1 ; Point3d ptP ; if ( ! PL.GetFirstPoint( ptP)) return false ; - ++ nP ; if ( AddVertex( ptP) == SVT_NULL || AddVertex( ptP + vtExtr) == SVT_NULL) return false ; nV += 2 ; // ciclo sui punti della polilinea (per inserire vertice e suo estruso + 2 triangoli per ogni punto) + int nIdV[4] ; + while ( PL.GetNextPoint( ptP, bClosed)) { + // aggiungo due nuovi vertici + if ( AddVertex( ptP) == SVT_NULL || AddVertex( ptP + vtExtr) == SVT_NULL) + return false ; + nV += 2 ; + // aggiungo i due triangoli relativi + nIdV[0] = nV - 2 ; + nIdV[1] = nV - 3 ; + nIdV[2] = nV - 1 ; + nIdV[3] = nV ; + if ( ! AddBiTriangle( nIdV)) + return false ; + } + // se curva chiusa, aggiungo gli ultimi due triangoli + if ( bClosed) { + // non devo aggiungere i vertici, perchè coincidono con quelli iniziali + // aggiungo i due triangoli relativi + nIdV[0] = nV ; + nIdV[1] = nV - 1 ; + nIdV[2] = 0 ; + nIdV[3] = 1 ; + if ( ! AddBiTriangle( nIdV)) + return false ; + } + + // sistemo la topologia + return AdjustTopology() ; +} + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::CreateByTwoCurves( const PolyLine& PL1, const PolyLine& PL2) +{ + // verifico validità polilinee (devono avere almeno 2 punti e non coincidere se non agli estremi aperti) + if ( ! VerifyPolylinesForTwoCurves( PL1, PL2)) + return false ; + // flag di curve chiuse + bool bClosed = PL1.IsClosed() && PL2.IsClosed() ; + // recupero i parametri delle due polilinee + double dU1F ; PL1.GetFirstU( dU1F) ; + double dU1L ; PL1.GetLastU( dU1L) ; + double dDeltaU1 = dU1L - dU1F ; + if ( dDeltaU1 < EPS_SMALL) + return false ; + double dU2F ; PL2.GetFirstU( dU2F) ; + double dU2L ; PL2.GetLastU( dU2L) ; + double dDeltaU2 = dU2L - dU2F ; + if ( dDeltaU2 < EPS_SMALL) + return false ; + + // costruisco la mesh + int nPointNbr = PL1.GetPointNbr() + PL2.GetPointNbr() ; + if ( ! Init( nPointNbr, nPointNbr)) + return false ; + + // recupero i punti iniziali su curva 1 + int nV1p ; double dU1p ; double dA1p ; Point3d ptP1p ; + int nV1s ; double dU1s ; double dA1s ; Point3d ptP1s ; + bool bNext1 = PL1.GetFirstUPoint( &dU1p, &ptP1p) && PL1.GetNextUPoint( &dU1s, &ptP1s, bClosed) ; + if ( ! bNext1) + return false ; + dA1p = 0 ; + dA1s = ( dU1s - dU1F) / dDeltaU1 ; + if ( ( nV1p = AddVertex( ptP1p)) == SVT_NULL) + return false ; + // recupero i punti iniziali su curva 2 + int nV2p ; double dU2p ; double dA2p ; Point3d ptP2p ; + int nV2s ; double dU2s ; double dA2s ; Point3d ptP2s ; + bool bNext2 = PL2.GetFirstUPoint( &dU2p, &ptP2p) && PL2.GetNextUPoint( &dU2s, &ptP2s, bClosed) ; + if ( ! bNext2) + return false ; + dA2p = 0 ; + dA2s = ( dU2s - dU2F) / dDeltaU2 ; int nIdV[3] ; - while ( PL.GetNextPoint( ptP)) { - // incremento numero punto - ++ nP ; - // se polilinea aperta o non è l'ultimo punto - if ( ! bClosed || nP < nPointNbr) { - // aggiungo due nuovi vertici - if ( AddVertex( ptP) == SVT_NULL || AddVertex( ptP + vtExtr) == SVT_NULL) + // se i punti iniziali non coincidono, inserisco il vertice iniziale di 2 + if ( ! AreSamePointNear( ptP1p, ptP2p)) { + if ( ( nV2p = AddVertex( ptP2p)) == SVT_NULL) + return false ; + } + // altrimenti, inserisco un triangolo e mi sposto in avanti su entrambe le curve + else { + // inserisco il vertice A1s + if ( ( nV1s = AddVertex( ptP1s)) == SVT_NULL) + return false ; + // inserisco il vertice A2s + if ( ( nV2s = AddVertex( ptP2s)) == SVT_NULL) + return false ; + // inserisco il triangolo A1p -> A1s -> A2s + nIdV[0] = nV1p ; + nIdV[1] = nV1s ; + nIdV[2] = nV2s ; + if ( AddTriangle( nIdV) == SVT_NULL) + return false ; + // passo al punto successivo su 1 + nV1p = nV1s ; dA1p = dA1s ; dU1p = dU1s ; ptP1p = ptP1s ; + bNext1 = PL1.GetNextUPoint( &dU1s, &ptP1s, bClosed) ; + if ( bNext1) + dA1s = ( dU1s - dU1F) / dDeltaU1 ; + // passo al punto successivo su 2 + nV2p = nV2s ; dA2p = dA2s ; dU2p = dU2s ; ptP2p = ptP2s ; + bNext2 = PL2.GetNextUPoint( &dU2s, &ptP2s, bClosed) ; + if ( bNext2) + dA2s = ( dU2s - dU2F) / dDeltaU2 ; + } + // ciclo sui punti + while ( bNext1 || bNext2) { + // se la diagonale più corta è dA2p -> dA1s + if ( ( dA1s - dA2p) <= ( dA2s - dA1p) + EPS_PARAM) { + // inserisco il vertice A1s + if ( ( nV1s = AddVertex( ptP1s)) == SVT_NULL) return false ; - nV += 2 ; - // aggiungo triangolo in basso a sinistra - nIdV[0] = nV - 3 ; nIdV[1] = nV - 1 ; nIdV[2] = nV - 2 ; + // inserisco il triangolo A2p -> A1p -> A1s + nIdV[0] = nV2p ; + nIdV[1] = nV1p ; + nIdV[2] = nV1s ; if ( AddTriangle( nIdV) == SVT_NULL) return false ; - // aggiungo triangolo in alto a destra - nIdV[0] = nV - 2 ; nIdV[1] = nV - 1 ; nIdV[2] = nV ; + // se i punti correnti coincidono passo al successivo anche su 2 + if ( AreSamePointNear( ptP1s, ptP2s)) { + nV2p = nV2s ; dA2p = dA2s ; dU2p = dU2s ; ptP2p = ptP2s ; + bNext2 = PL2.GetNextUPoint( &dU2s, &ptP2s, bClosed) ; + if ( bNext2) + dA2s = ( dU2s - dU2F) / dDeltaU2 ; + } + // passo al punto successivo su 1 + nV1p = nV1s ; dA1p = dA1s ; dU1p = dU1s ; ptP1p = ptP1s ; + bNext1 = PL1.GetNextUPoint( &dU1s, &ptP1s, bClosed) ; + if ( bNext1) + dA1s = ( dU1s - dU1F) / dDeltaU1 ; + } + // altrimenti è dA1p -> dA2s + else { + // inserisco il vertice A2s + if ( ( nV2s = AddVertex( ptP2s)) == SVT_NULL) + return false ; + // inserisco il triangolo A2p -> A1p -> A2s + nIdV[0] = nV2p ; + nIdV[1] = nV1p ; + nIdV[2] = nV2s ; + if ( AddTriangle( nIdV) == SVT_NULL) + return false ; + // se i punti correnti coincidono passo al successivo anche su 1 + if ( AreSamePointNear( ptP1s, ptP2s)) { + nV1p = nV1s ; dA1p = dA1s ; dU1p = dU1s ; ptP1p = ptP1s ; + bNext1 = PL1.GetNextUPoint( &dU1s, &ptP1s, bClosed) ; + if ( bNext1) + dA1s = ( dU1s - dU1F) / dDeltaU1 ; + } + // passo al punto successivo su 2 + nV2p = nV2s ; dA2p = dA2s ; dU2p = dU2s ; ptP2p = ptP2s ; + bNext2 = PL2.GetNextUPoint( &dU2s, &ptP2s, bClosed) ; + if ( bNext2) + dA2s = ( dU2s - dU2F) / dDeltaU2 ; + } + } + // se curve chiuse, aggiungo gli ultimi due triangoli + if ( bClosed) { + dA1s = 1 ; + dA2s = 1 ; + // se la diagonale più corta è dA2p -> dA1s = 0 + if ( ( dA1s - dA2p) <= ( dA2s - dA1p) + EPS_PARAM) { + // inserisco il triangolo A2p -> A1p -> A1s = 0 + nIdV[0] = nV2p ; + nIdV[1] = nV1p ; + nIdV[2] = 0 ; + if ( AddTriangle( nIdV) == SVT_NULL) + return false ; + // inserisco il triangolo A2p -> A1s = 0 -> A2s = 1 + nIdV[0] = nV2p ; + nIdV[1] = 0 ; + nIdV[2] = 1 ; if ( AddTriangle( nIdV) == SVT_NULL) return false ; } - // altrimenti ultimo punto di polilinea chiusa + // altrimenti è dA1p -> dA2s = 1 else { - // non devo aggiungere i vertici, perchè coincidono con quelli iniziali - // aggiungo triangolo in basso a sinistra - nIdV[0] = nV - 1 ; nIdV[1] = 0 ; nIdV[2] = nV ; + // inserisco il triangolo A2p -> A1p -> A2s = 1 + nIdV[0] = nV2p ; + nIdV[1] = nV1p ; + nIdV[2] = 1 ; if ( AddTriangle( nIdV) == SVT_NULL) return false ; - // aggiungo triangolo in alto a destra - nIdV[0] = nV ; nIdV[1] = 0 ; nIdV[2] = 1 ; + // inserisco il triangolo A1p -> A1s = 0 -> A2s = 1 + nIdV[0] = nV1p ; + nIdV[1] = 0 ; + nIdV[2] = 1 ; if ( AddTriangle( nIdV) == SVT_NULL) return false ; } @@ -848,21 +1009,107 @@ SurfTriMesh::CreateByExtrusion( const PolyLine& PL, const Vector3d& vtExtr) return AdjustTopology() ; } +//---------------------------------------------------------------------------- +bool +SurfTriMesh::VerifyPolylinesForTwoCurves( const PolyLine& PL1, const PolyLine& PL2) const +{ + // recupero se chiusa + bool bClosed = PL1.IsClosed() && PL2.IsClosed() ; + // se chiuse, devono avere almeno 3 punti + if ( bClosed) { + if ( PL1.GetPointNbr() < 3 || PL2.GetPointNbr() < 3) + return false ; + } + // se aperte, almeno 2 + else { + if ( PL1.GetPointNbr() < 2 || PL2.GetPointNbr() < 2) + return false ; + } + + // verifico che non ci siano punti interni in comune a pari parametro + // recupero i parametri delle due polilinee + double dU1F ; PL1.GetFirstU( dU1F) ; + double dU1L ; PL1.GetLastU( dU1L) ; + double dDeltaU1 = dU1L - dU1F ; + if ( dDeltaU1 < EPS_SMALL) + return false ; + double dU2F ; PL2.GetFirstU( dU2F) ; + double dU2L ; PL2.GetLastU( dU2L) ; + double dDeltaU2 = dU2L - dU2F ; + if ( dDeltaU2 < EPS_SMALL) + return false ; + // ciclo sui punti + double dA1p ; double dU1p ; Point3d ptP1p ; + double dA1s ; double dU1s ; Point3d ptP1s ; + bool bNext1 = PL1.GetFirstUPoint( &dU1p, &ptP1p) && PL1.GetNextUPoint( &dU1s, &ptP1s) ; + if ( ! bNext1) + return false ; + dA1p = 0 ; + dA1s = ( dU1s - dU1F) / dDeltaU1 ; + double dA2p ; double dU2s ; Point3d ptP2s ; + double dA2s ; double dU2p ; Point3d ptP2p ; + bool bNext2 = PL2.GetFirstUPoint( &dU2p, &ptP2p) && PL2.GetNextUPoint( &dU2s, &ptP2s) ; + if ( ! bNext2) + return false ; + dA2p = 0 ; + dA2s = ( dU2s - dU2F) / dDeltaU2 ; + // se chiuse, verifico la coincidenza dell'inizio delle due curve + if ( bClosed && AreSamePointNear( ptP1p, ptP2p)) + return false ; + // verifiche sui punti successivi (non sugli ultimi) + while ( bNext1 || bNext2) { + // se la diagonale più corta è dA2p -> dA1s + if ( ( dA1s - dA2p) <= ( dA2s - dA1p) + EPS_PARAM) { + // verifico se coincidono + if ( AreSamePointNear( ptP2p, ptP1s)) + return false ; + // passo al punto successivo su 1 + dA1p = dA1s ; dU1p = dU1s ; ptP1p = ptP1s ; + bNext1 = PL1.GetNextUPoint( &dU1s, &ptP1s, true) ; + if ( bNext1) + dA1s = ( dU1s - dU1F) / dDeltaU1 ; + } + // altrimenti è dA1p -> dA2s = 1 + else { + // verifico se coincidono + if ( AreSamePointNear( ptP1p, ptP2s)) + return false ; + // passo al punto successivo su 2 + dA2p = dA2s ; dU2p = dU2s ; ptP2p = ptP2s ; + bNext2 = PL2.GetNextUPoint( &dU2s, &ptP2s, true) ; + if ( bNext2) + dA2s = ( dU2s - dU2F) / dDeltaU2 ; + } + } + + return true ; +} + //---------------------------------------------------------------------------- bool SurfTriMesh::CreateByRevolution( const PolyLine& PL, const Point3d& ptAx, const Vector3d& vtAx, double dAngRot, double dStepRot) +{ + return CreateByScrewing( PL, ptAx, vtAx, dAngRot, dStepRot, 0) ; +} + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::CreateByScrewing( const PolyLine& PL, const Point3d& ptAx, const Vector3d& vtAx, + double dAngRot, double dStepRot, double dMove) { // verifico che l'asse di rotazione sia non nullo if ( vtAx.IsSmall()) return false ; - // verifico che l'angolo di rotazione sia significativo e non superi un giro + // verifico se solo rivoluzione + bool bOnlyRev = ( fabs( dMove) < EPS_SMALL) ; + // verifico che l'angolo di rotazione sia significativo e, se solo rivoluzione, non superi un giro if ( fabs( dAngRot) < EPS_ANG_SMALL) return false ; - if ( fabs( dAngRot) > ANG_FULL) + if ( bOnlyRev && fabs( dAngRot) > ANG_FULL) dAngRot = _copysign( ANG_FULL, dAngRot) ; // verifico se rotazione completa - bool bFullRev = ( fabs( fabs( dAngRot) - ANG_FULL) < EPS_ANG_SMALL) ; + bool bFullRev = bOnlyRev && ( fabs( fabs( dAngRot) - ANG_FULL) < EPS_ANG_SMALL) ; // aggiusto il valore dell'angolo di step const double MIN_STEP_ROT = 1 ; const double MAX_STEP_ROT = 90 ; @@ -875,7 +1122,9 @@ SurfTriMesh::CreateByRevolution( const PolyLine& PL, const Point3d& ptAx, const // calcolo il numero di step int nStep = int( dAngRot / dStepRot) ; nStep = max( nStep, 1) ; - dStepRot = dAngRot / nStep ; + double dCosStepRot = cos( dAngRot / nStep * DEGTORAD) ; + double dSinStepRot = sin( dAngRot / nStep * DEGTORAD) ; + Vector3d vtStepMove = ( dMove / nStep) * vtAx ; if ( bFullRev) -- nStep ; @@ -894,24 +1143,24 @@ SurfTriMesh::CreateByRevolution( const PolyLine& PL, const Point3d& ptAx, const return false ; // inserisco il primo punto della polilinea e i suoi ruotati - int nP = 0 ; int nV = -1 ; Point3d ptP ; // recupero il punto if ( ! PL.GetFirstPoint( ptP)) return false ; - ++ nP ; // inserisco il primo vertice if ( AddVertex( ptP) == SVT_NULL) return false ; ++ nV ; - // verifico se il punto giace sull'asse - bool bPrevOnAx = DistPointLine( ptP, ptAx, vtAx, 1, false).IsSmall() ; + // verifico se il punto giace sull'asse e vi sta fisso + bool bPrevOnAx = bOnlyRev && DistPointLine( ptP, ptAx, vtAx, 1, false).IsSmall() ; int nVPrevOnAx = nV ; - // se non è sull'asse, inserisco le copie ruotate + // se non è fisso sull'asse, inserisco le copie ruotate if ( ! bPrevOnAx) { for ( int i = 1 ; i <= nStep ; ++i) { - ptP.Rotate( ptAx, vtAx, dStepRot * DEGTORAD) ; + ptP.Rotate( ptAx, vtAx, dCosStepRot, dSinStepRot) ; + if ( ! bOnlyRev) + ptP.Translate( vtStepMove) ; if ( AddVertex( ptP) == SVT_NULL) return false ; ++ nV ; @@ -919,108 +1168,105 @@ SurfTriMesh::CreateByRevolution( const PolyLine& PL, const Point3d& ptAx, const } // ciclo sui punti della polilinea (per inserire vertice e suoi ruotati + 2 triangoli per ogni punto) int nIdV[4] ; - while ( PL.GetNextPoint( ptP)) { - // incremento numero punto - ++ nP ; - // se polilinea aperta o non è l'ultimo punto - if ( ! bClosed || nP < nPointNbr) { - // aggiungo il primo vertice - if ( AddVertex( ptP) == SVT_NULL) - return false ; - ++ nV ; - // verifico se il punto giace sull'asse - bool bOnAx = DistPointLine( ptP, ptAx, vtAx, 1, false).IsSmall() ; - // ciclo sugli step - for ( int i = 1 ; i <= nStep ; ++i) { - // se non è sull'asse, inserisco le copie ruotate - if ( ! bOnAx) { - ptP.Rotate( ptAx, vtAx, dStepRot * DEGTORAD) ; - if ( AddVertex( ptP) == SVT_NULL) - return false ; - ++ nV ; - } - // per i controlli già fatti non è possibile avere contemp. prec e corr su asse - // se il precedente è sull'asse, aggiungo un solo triangolo - if ( bPrevOnAx) { - nIdV[0] = nVPrevOnAx ; - nIdV[1] = nV ; - nIdV[2] = nV - 1 ; - if ( AddTriangle( nIdV) == SVT_NULL) - return false ; - } - // se il corrente è sull'asse, aggiungo un solo triangolo - else if ( bOnAx) { - nIdV[0] = nV - ( nStep + 2) + i ; - nIdV[1] = nIdV[0] + 1 ; - nIdV[2] = nV ; - if ( AddTriangle( nIdV) == SVT_NULL) - return false ; - } - // altrimenti aggiungo due triangoli - else { - nIdV[0] = nV - ( nStep + 2) ; - nIdV[1] = nIdV[0] + 1 ; - nIdV[2] = nV ; - nIdV[3] = nV - 1 ; - if ( ! AddBiTriangle( nIdV)) - return false ; - } + while ( PL.GetNextPoint( ptP, bClosed)) { + // aggiungo il primo vertice + if ( AddVertex( ptP) == SVT_NULL) + return false ; + ++ nV ; + // verifico se il punto giace sull'asse e vi sta fisso + bool bOnAx = bOnlyRev && DistPointLine( ptP, ptAx, vtAx, 1, false).IsSmall() ; + // ciclo sugli step + for ( int i = 1 ; i <= nStep ; ++i) { + // se non è fisso sull'asse, inserisco le copie ruotate + if ( ! bOnAx) { + ptP.Rotate( ptAx, vtAx, dCosStepRot, dSinStepRot) ; + if ( ! bOnlyRev) + ptP.Translate( vtStepMove) ; + if ( AddVertex( ptP) == SVT_NULL) + return false ; + ++ nV ; } - // se rivoluzione completa, aggiungo i due triangoli di chiusura - if ( bFullRev) { - // per i controlli già fatti non è possibile avere contemp. prec e corr su asse - // se il precedente è sull'asse, aggiungo un solo triangolo - if ( bPrevOnAx) { - nIdV[0] = nVPrevOnAx ; - nIdV[1] = nV - nStep ; - nIdV[2] = nV ; - if ( AddTriangle( nIdV) == SVT_NULL) - return false ; - } - // se il corrente è sull'asse, aggiungo un solo triangolo - else if ( bOnAx) { - nIdV[0] = nV - 1 ; - nIdV[1] = nV - ( nStep + 1) ; - nIdV[2] = nV ; - if ( AddTriangle( nIdV) == SVT_NULL) - return false ; - } - // altrimenti aggiungo due triangoli - else { - nIdV[0] = nV - ( nStep + 1) ; - nIdV[1] = nV - ( 2 * nStep + 1) ; - nIdV[2] = nV - nStep ; - nIdV[3] = nV ; - if ( ! AddBiTriangle( nIdV)) - return false ; - } + // per i controlli già fatti non è possibile avere contemp. prec e corr su asse + // se il precedente è sull'asse, aggiungo un solo triangolo + if ( bPrevOnAx) { + nIdV[0] = nVPrevOnAx ; + nIdV[1] = nV ; + nIdV[2] = nV - 1 ; + if ( AddTriangle( nIdV) == SVT_NULL) + return false ; + } + // se il corrente è sull'asse, aggiungo un solo triangolo + else if ( bOnAx) { + nIdV[0] = nV - ( nStep + 2) + i ; + nIdV[1] = nIdV[0] + 1 ; + nIdV[2] = nV ; + if ( AddTriangle( nIdV) == SVT_NULL) + return false ; + } + // altrimenti aggiungo due triangoli + else { + nIdV[0] = nV - ( nStep + 2) ; + nIdV[1] = nIdV[0] + 1 ; + nIdV[2] = nV ; + nIdV[3] = nV - 1 ; + if ( ! AddBiTriangle( nIdV)) + return false ; } - bPrevOnAx = false ; } - // altrimenti ultimo punto di polilinea chiusa - else { - for ( int i = 1 ; i <= nStep ; ++i) { - // non devo aggiungere i vertici, perchè coincidono con quelli iniziali - // aggiungo triangolo in basso a sinistra - nIdV[0] = nV - nStep + i - 1 ; nIdV[1] = nV - nStep + i ; nIdV[2] = i ; - if ( AddTriangle( nIdV) == SVT_NULL) - return false ; - // aggiungo triangolo in alto a destra - nIdV[0] = nV - nStep + i - 1 ; nIdV[1] = i ; nIdV[2] = i - 1 ; + // se rivoluzione completa, aggiungo i due triangoli di chiusura + if ( bFullRev) { + // per i controlli già fatti non è possibile avere contemp. prec e corr su asse + // se il precedente è sull'asse, aggiungo un solo triangolo + if ( bPrevOnAx) { + nIdV[0] = nVPrevOnAx ; + nIdV[1] = nV - nStep ; + nIdV[2] = nV ; if ( AddTriangle( nIdV) == SVT_NULL) return false ; } - // se rivoluzione completa, aggiungo i due triangoli di chiusura - if ( bFullRev) { - // aggiungo triangolo in basso a sinistra - nIdV[0] = nV ; nIdV[1] = nV - nStep ; nIdV[2] = 0 ; - if ( AddTriangle( nIdV) == SVT_NULL) - return false ; - // aggiungo triangolo in alto a destra - nIdV[0] = nV ; nIdV[1] = 0 ; nIdV[2] = nStep ; + // se il corrente è sull'asse, aggiungo un solo triangolo + else if ( bOnAx) { + nIdV[0] = nV - 1 ; + nIdV[1] = nV - ( nStep + 1) ; + nIdV[2] = nV ; if ( AddTriangle( nIdV) == SVT_NULL) return false ; } + // altrimenti aggiungo due triangoli + else { + nIdV[0] = nV - ( nStep + 1) ; + nIdV[1] = nV - ( 2 * nStep + 1) ; + nIdV[2] = nV - nStep ; + nIdV[3] = nV ; + if ( ! AddBiTriangle( nIdV)) + return false ; + } + } + bPrevOnAx = false ; + } + // altrimenti ultimo punto di polilinea chiusa + if ( bClosed) { + for ( int i = 1 ; i <= nStep ; ++i) { + // non devo aggiungere i vertici, perchè coincidono con quelli iniziali + // aggiungo triangolo in basso a sinistra + nIdV[0] = nV - nStep + i - 1 ; nIdV[1] = nV - nStep + i ; nIdV[2] = i ; + if ( AddTriangle( nIdV) == SVT_NULL) + return false ; + // aggiungo triangolo in alto a destra + nIdV[0] = nV - nStep + i - 1 ; nIdV[1] = i ; nIdV[2] = i - 1 ; + if ( AddTriangle( nIdV) == SVT_NULL) + return false ; + } + // se rivoluzione completa, aggiungo i due triangoli di chiusura + if ( bFullRev) { + // aggiungo triangolo in basso a sinistra + nIdV[0] = nV ; nIdV[1] = nV - nStep ; nIdV[2] = 0 ; + if ( AddTriangle( nIdV) == SVT_NULL) + return false ; + // aggiungo triangolo in alto a destra + nIdV[0] = nV ; nIdV[1] = 0 ; nIdV[2] = nStep ; + if ( AddTriangle( nIdV) == SVT_NULL) + return false ; } } @@ -1078,9 +1324,9 @@ SurfTriMesh::AddBiTriangle( const int nIdVert[4]) // | | // 1 -> 2 int nIdV[3] ; - // se la diagonale 0->2 è più corta della 1->3 + // se la diagonale 0->2 è uguale o più corta della 1->3 if ( SqDist( m_vVert[nIdVert[0]].ptP, m_vVert[nIdVert[2]].ptP) <= - SqDist( m_vVert[nIdVert[1]].ptP, m_vVert[nIdVert[3]].ptP)) { + SqDist( m_vVert[nIdVert[1]].ptP, m_vVert[nIdVert[3]].ptP) + EPS_SMALL) { // triangolo 0->1->2 nIdV[0] = nIdVert[0] ; nIdV[1] = nIdVert[1] ; diff --git a/SurfTriMesh.h b/SurfTriMesh.h index 111894b..7b1ed28 100644 --- a/SurfTriMesh.h +++ b/SurfTriMesh.h @@ -95,10 +95,13 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW virtual int AddVertex( const Point3d& ptVert) ; virtual int AddTriangle( const int nIdVert[3]) ; virtual bool AdjustTopology( void) ; - virtual bool CreateByTriangulation( const PolyLine& PL) ; + virtual bool CreateByFlatContour( const PolyLine& PL) ; 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, double dAngRot, double dStepRot) ; + virtual bool CreateByScrewing( const PolyLine& PL, const Point3d& ptAx, const Vector3d& vtAx, + double dAngRot, double dStepRot, double dMove) ; virtual int GetVertexNum( void) const { return int( m_vVert.size()) ; } virtual int GetTriangleNum( void) const @@ -140,8 +143,9 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW int NextIndAroundVertex( int nInd, int nSize, bool bCirc) const ; int PrevIndAroundVertex( int nInd, int nSize, bool bCirc) const ; bool GetTriangleSmoothNormal( int nT, int nV, Vector3d& vtN) const ; + bool VerifyPolylinesForTwoCurves( const PolyLine& PL1, const PolyLine& PL2) const ; bool VeryfyPolylineForRevolution( const PolyLine& PL, const Point3d& ptAx, const Vector3d& vtAx) const ; - bool AddBiTriangle( const int nIdVert[4]) ; + bool AddBiTriangle( const int nIdVert[4]) ; private : enum Status { ERR = 0, OK = 1, TO_VERIFY = 2} ;