diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index b9d6c9d..c68c1a3 100644 Binary files a/EgtGeomKernel.rc and b/EgtGeomKernel.rc differ diff --git a/GdbExecutor.cpp b/GdbExecutor.cpp index cb997b2..523c73c 100644 --- a/GdbExecutor.cpp +++ b/GdbExecutor.cpp @@ -2425,7 +2425,7 @@ GdbExecutor::SurfTriMeshByTwoPaths( const STRVECTOR& vsParams) if ( vsParams.size() == 5) FromString( vsParams[4], dLinTol) ; // calcolo la superficie - ISurfTriMesh* pSTM = GetSurfTriMeshRuled( CrvLoc1, CrvLoc2, dLinTol) ; + ISurfTriMesh* pSTM = GetSurfTriMeshRuled( CrvLoc1, CrvLoc2, ISurfTriMesh::RLT_ISOPAR, dLinTol) ; if ( pSTM == nullptr) return false ; // inserisco la superficie trimesh nel DB diff --git a/OffsetCurve.cpp b/OffsetCurve.cpp index ef8d708..0c00934 100644 --- a/OffsetCurve.cpp +++ b/OffsetCurve.cpp @@ -43,6 +43,13 @@ static bool ModifyFillet( ICurve* pCrv, double dDist, int nType, CurveComposite& //---------------------------------------------------------------------------- OffsetCurve::~OffsetCurve( void) +{ + Reset() ; +} + +//---------------------------------------------------------------------------- +bool +OffsetCurve::Reset( void) { for ( auto& pCrv : m_CrvLst) { if ( pCrv != nullptr) { @@ -51,12 +58,15 @@ OffsetCurve::~OffsetCurve( void) } } m_CrvLst.clear() ; + return true ; } //---------------------------------------------------------------------------- bool OffsetCurve::Make( const ICurve* pCrv, double dDist, int nType) { + // pulisco tutto + Reset() ; // verifico che la curva esista e sia piana Plane3d plPlane ; if ( pCrv == nullptr || ! pCrv->IsFlat( plPlane)) @@ -73,6 +83,21 @@ OffsetCurve::Make( const ICurve* pCrv, double dDist, int nType) double dThick ; pCrv->GetThickness( dThick) ; + // se offset nullo, copio la curva ed esco + if ( abs( dDist) < 10 * EPS_SMALL) { + PtrOwner< CurveComposite> pCopy( CreateBasicCurveComposite()) ; + if ( IsNull( pCopy) || ! pCopy->CopyFrom( pCrv)) + return false ; + // assegno estrusione e spessore come curva originale + pCopy->SetExtrusion( vtExtr) ; + pCopy->SetThickness( dThick) ; + // unisco parti allineate (tranne gli estremi) + pCopy->MergeCurves( 10 * EPS_SMALL, ANG_TOL_STD_DEG, false) ; + // sposto in lista + m_CrvLst.push_back( Release( pCopy)) ; + return true ; + } + // determino se necessario cambiare riferimento ( dal vettore estrusione) bool bNeedRef = ( ! vtExtr.IsZplus()) ; diff --git a/PointsPCA.cpp b/PointsPCA.cpp index 9d51956..ec7874c 100644 --- a/PointsPCA.cpp +++ b/PointsPCA.cpp @@ -20,7 +20,7 @@ PointsPCA::PointsPCA( void) { // azzero numero punti - m_nPntNbr = 0 ; + m_dTotW = 0 ; // azzero il baricentro m_ptCen.Set( 0, 0, 0) ; // azzero matrice di covarianza @@ -31,19 +31,19 @@ PointsPCA::PointsPCA( void) //---------------------------------------------------------------------------- void -PointsPCA::AddPoint( const Point3d& ptP) +PointsPCA::AddPoint( const Point3d& ptP, double dW) { // incremento numero punti - ++ m_nPntNbr ; + m_dTotW += dW ; // aggiorno il baricentro - m_ptCen += ptP ; + m_ptCen += dW * ptP ; // aggiorno la matrice di covarianza (solo triangolo superiore perchè simmetrica) - m_CovMat(0,0) += ptP.x * ptP.x ; - m_CovMat(1,1) += ptP.y * ptP.y ; - m_CovMat(2,2) += ptP.z * ptP.z ; - m_CovMat(0,1) += ptP.x * ptP.y ; - m_CovMat(0,2) += ptP.x * ptP.z ; - m_CovMat(1,2) += ptP.y * ptP.z ; + m_CovMat(0,0) += dW * ( ptP.x * ptP.x) ; + m_CovMat(1,1) += dW * ( ptP.y * ptP.y) ; + m_CovMat(2,2) += dW * ( ptP.z * ptP.z) ; + m_CovMat(0,1) += dW * ( ptP.x * ptP.y) ; + m_CovMat(0,2) += dW * ( ptP.x * ptP.z) ; + m_CovMat(1,2) += dW * ( ptP.y * ptP.z) ; } //---------------------------------------------------------------------------- @@ -58,11 +58,11 @@ PointsPCA::Finalize( void) m_nRank = 0 ; // se non sono stati assegnati punti, esco - if ( m_nPntNbr == 0) + if ( m_dTotW < EPS_ZERO) return false ; // fattore di scala per numero di punti - double dScale = 1 / double( m_nPntNbr) ; + double dScale = 1 / m_dTotW ; // calcolo del baricentro m_ptCen *= dScale ; @@ -146,7 +146,7 @@ PointsPCA::GetCenter( Point3d& ptCen) Finalize() ; // assegno i dati ptCen = m_ptCen ; - return ( m_nPntNbr > 0) ; + return ( m_dTotW > EPS_ZERO) ; } //---------------------------------------------------------------------------- diff --git a/PointsPCA.h b/PointsPCA.h index 0aceff0..f628a87 100644 --- a/PointsPCA.h +++ b/PointsPCA.h @@ -21,7 +21,7 @@ class PointsPCA { public : PointsPCA( void) ; - void AddPoint( const Point3d& ptP) ; + void AddPoint( const Point3d& ptP, double dW = 1) ; int GetRank( void) ; bool GetCenter( Point3d& ptCen) ; bool GetPrincipalComponent( int nId, Vector3d& vtPC) ; @@ -33,7 +33,7 @@ class PointsPCA static const int MAX_RANK = 3 ; private : - int m_nPntNbr ; // numero punti + double m_dTotW ; // peso totale (se pesi tutti unitari, allora è numero punti) Point3d m_ptCen ; // baricentro Eigen::Matrix3d m_CovMat ; // matrice di covarianza int m_nRank ; // numero delle componenti principali (MAX_RANK = 3) diff --git a/PolyLine.cpp b/PolyLine.cpp index 135aabc..8e102b5 100644 --- a/PolyLine.cpp +++ b/PolyLine.cpp @@ -49,19 +49,37 @@ PolyLine::Clear( void) //---------------------------------------------------------------------------- bool -PolyLine::AddUPoint( double dPar, const Point3d& ptP) +PolyLine::AddUPoint( double dPar, const Point3d& ptP, bool bEndOrStart) { - // se il punto è uguale al precedente (ignoro parametro), non lo inserisco ma ok - if ( m_lUPoints.size() > 0 && AreSamePointApprox( ptP, m_lUPoints.back().first)) { - ++ m_nRejected ; - return true ; + // se da aggiungere in coda + if ( bEndOrStart) { + // se il punto è uguale all'ultimo (ignoro parametro), non lo inserisco ma ok + if ( m_lUPoints.size() > 0 && AreSamePointApprox( ptP, m_lUPoints.back().first)) { + ++ m_nRejected ; + return true ; + } + // eseguo inserimento + try { + m_lUPoints.emplace_back( ptP, dPar) ; + } + catch (...) { + return false ; + } } - // eseguo inserimento - try { - m_lUPoints.emplace_back( ptP, dPar) ; - } - catch (...) { - return false ; + // altrimenti si aggiunge in testa + else { + // se il punto è uguale al primo (ignoro parametro), non lo inserisco ma ok + if ( m_lUPoints.size() > 0 && AreSamePointApprox( ptP, m_lUPoints.front().first)) { + ++ m_nRejected ; + return true ; + } + // eseguo inserimento + try { + m_lUPoints.emplace_front( ptP, dPar) ; + } + catch (...) { + return false ; + } } return true ; @@ -494,10 +512,10 @@ bool PolyLine::IsFlat( int& nRank, Point3d& ptCen, Vector3d& vtDir, double dToler) const { // cerco le componenti principali (tramite PCA) - Point3d ptP ; + Point3d ptP1, ptP2 ; PointsPCA ptsPCA ; - for ( bool bFound = GetFirstPoint( ptP) ; bFound ; bFound = GetNextPoint( ptP)) - ptsPCA.AddPoint( ptP) ; + for ( bool bFound = GetFirstLine( ptP1, ptP2) ; bFound ; bFound = GetNextLine( ptP1, ptP2)) + ptsPCA.AddPoint( Media( ptP1, ptP2), Dist( ptP1, ptP2)) ; // recupero il rango, ovvero la dimensionalità dell'insieme di punti nRank = ptsPCA.GetRank() ; // se dimensione nulla, o non ci sono punti o sono tutti praticamente coincidenti @@ -531,6 +549,7 @@ PolyLine::IsFlat( int& nRank, Point3d& ptCen, Vector3d& vtDir, double dToler) co Plane3d plPlane ; plPlane.Set( ptCen, vtDir) ; // Test each vertex to see if it is farther from plane than allowed max distance + Point3d ptP ; for ( bool bFound = GetFirstPoint( ptP) ; bFound ; bFound = GetNextPoint( ptP)) { double dDist = ( ( ptP - ORIG) * plPlane.GetVersN()) - plPlane.GetDist() ; if ( abs( dDist) > dToler) @@ -765,19 +784,19 @@ PolyLine::ApproxOnSide( const Vector3d& vtN, bool bLeftSide, double dToler) // *** polilinea chiusa : devo sistemare a cavallo dell'inizio/fine *** // sposto l'inizio dalla parte opposta - MyChangeStartOnMiddle() ; + MyChangeStart( int( m_lUPoints.size() / 2)) ; // rifaccio l'approssimazione con 3/4 della tolleranza ammessa if ( ! MyApproxOnSide( vtN, bLeftSide, 0.75 * dToler)) return false ; // risposto l'inizio dalla parte opposta, quindi lo porto vicino all'originale - MyChangeStartOnMiddle() ; + MyChangeStart( int( m_lUPoints.size() / 2)) ; return true ; } //---------------------------------------------------------------------------- bool -PolyLine::MyChangeStartOnMiddle( void) +PolyLine::MyChangeStart( int nPos) { // solo per polilinee chiuse if ( ! IsClosed()) @@ -785,7 +804,7 @@ PolyLine::MyChangeStartOnMiddle( void) // cancello ultimo punto ( coincide con primo) m_lUPoints.pop_back() ; // sposto la metà iniziale dei punti alla fine - for ( size_t i = 0 ; i < m_lUPoints.size() / 2 ; ++ i) + for ( int i = 0 ; i < nPos ; ++ i) m_lUPoints.splice( m_lUPoints.end(), m_lUPoints, m_lUPoints.begin()) ; // aggiungo punto finale come copia dell'iniziale m_lUPoints.push_back( m_lUPoints.front()) ; @@ -916,12 +935,12 @@ PolyLine::MakeConvex( const Vector3d& vtN, bool bLeftSide) // *** polilinea chiusa : devo sistemare a cavallo dell'inizio/fine *** // sposto l'inizio dalla parte opposta - MyChangeStartOnMiddle() ; + MyChangeStart( int( m_lUPoints.size() / 2)) ; // rifaccio la modifica if ( ! MyMakeConvex( vtN, bLeftSide)) return false ; // risposto l'inizio dalla parte opposta, quindi lo porto vicino all'originale - MyChangeStartOnMiddle() ; + MyChangeStart( int( m_lUPoints.size() / 2)) ; return true ; } @@ -1195,3 +1214,57 @@ PolyLine::GetMinAreaRectangleXY( Point3d& ptCen, Vector3d& vtAx, double& dLen, d return true ; } + +//---------------------------------------------------------------------------- +bool +PolyLine::Trim( const Plane3d& plPlane, bool bInVsOut) +{ + // se vuota non faccio alcunché + if ( m_lUPoints.size() == 0) + return false ; + + // determino le intersezioni dei lati con il piano + int nIntPos = - 1 ; + auto prevUP = m_lUPoints.begin() ; + double dPrevDist = ( prevUP->first - ORIG) * plPlane.GetVersN() - plPlane.GetDist() ; + auto currUP = next( prevUP) ; + while ( currUP != m_lUPoints.end()) { + // se non inizializzato e precedente in zona vietata, ne salvo l'indice + if ( nIntPos == -1 && + ( ( bInVsOut && dPrevDist > EPS_SMALL) || + ( ! bInVsOut && dPrevDist < - EPS_SMALL))) + nIntPos = int( distance( m_lUPoints.begin(), prevUP)) ; + // distanze del punto dal piano + double dCurrDist = ( currUP->first - ORIG) * plPlane.GetVersN() - plPlane.GetDist() ; + // se il lato attraversa il piano, inserisco il punto di intersezione nel poligono + if ( ( dPrevDist > EPS_SMALL && dCurrDist < - EPS_SMALL) || + ( dPrevDist < - EPS_SMALL && dCurrDist > EPS_SMALL)) { + double dCoeff = abs( dPrevDist) / ( abs( dPrevDist) + abs( dCurrDist)) ; + Point3d ptInt = Media( prevUP->first, currUP->first, dCoeff) ; + double dU = ( 1 - dCoeff) * prevUP->second + dCoeff * currUP->second ; + m_lUPoints.insert( currUP, { ptInt, dU}) ; + } + // passo al successivo + prevUP = currUP ; + currUP = next( currUP) ; + dPrevDist = dCurrDist ; + } + + // se chiusa, sposto l'inizio su eventuale primo punto di intersezione con il piano + if ( IsClosed() && nIntPos != -1) + MyChangeStart( nIntPos) ; + + // elimino i punti che non rispettano la posizione rispetto al piano + currUP = m_lUPoints.begin() ; + while ( currUP != m_lUPoints.end()) { + double dDist = ( currUP->first - ORIG) * plPlane.GetVersN() - plPlane.GetDist() ; + if ( ( bInVsOut && dDist > EPS_SMALL) || + ( ! bInVsOut && dDist < - EPS_SMALL)) { + currUP = m_lUPoints.erase( currUP) ; + } + else + currUP = next( currUP) ; + } + + return true ; +} diff --git a/StmFromCurves.cpp b/StmFromCurves.cpp index 2072ea2..3e8c884 100644 --- a/StmFromCurves.cpp +++ b/StmFromCurves.cpp @@ -17,6 +17,7 @@ #include "CurveLine.h" #include "CurveArc.h" #include "CurveComposite.h" +#include "/EgtDev/Include/EgkOffsetCurve.h" #include "/EgtDev/Include/EGkStmFromCurves.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include @@ -244,6 +245,10 @@ GetSurfTriMeshByRevolve( const ICurve* pCurve, const Point3d& ptAx, const Vector PtrOwner pSTM( CreateSurfTriMesh()) ; if ( IsNull( pSTM) || ! pSTM->CreateByScrewing( PL, ptAx, vtAx, ANG_FULL, dStepRotDeg, 0)) return nullptr ; + // se superficie risultante chiusa, verifico che la normale sia verso l'esterno + double dVol ; + if ( pSTM->GetVolume( dVol) && dVol < 0) + pSTM->Invert() ; // salvo tolleranza lineare usata pSTM->SetLinearTolerance( dLinTol) ; // restituisco la superficie @@ -279,51 +284,16 @@ GetSurfTriMeshByScrewing( const ICurve* pCurve, const Point3d& ptAx, const Vecto PtrOwner pSTM( CreateSurfTriMesh()) ; if ( IsNull( pSTM) || ! pSTM->CreateByScrewing( PL, ptAx, vtAx, dAngRotDeg, dStepRotDeg, dMove)) return nullptr ; + // se superficie risultante chiusa, verifico che la normale sia verso l'esterno + double dVol ; + if ( pSTM->GetVolume( dVol) && dVol < 0) + pSTM->Invert() ; // salvo tolleranza lineare usata pSTM->SetLinearTolerance( dLinTol) ; // restituisco la superficie return Release( pSTM) ; } -//------------------------------------------------------------------------------- -static bool -AddSurfRev( ISurfTriMesh* pSTot, const PolyLine& PlSect, const Point3d& ptCen, const Vector3d& vtAx, double dAngRotDeg, double dLinTol) -{ - // calcolo lo step di rotazione - double dMaxRad = 0 ; - if ( ! PlSect.GetMaxDistanceFromLine( ptCen, vtAx, 1, dMaxRad, false) || dMaxRad < EPS_SMALL) - return false ; - double dStepRotDeg = sqrt( 8 * dLinTol / dMaxRad) * RADTODEG ; - // creo superficie di rivoluzione - PtrOwner pStm( CreateSurfTriMesh()) ; - if ( IsNull( pStm) || ! pStm->CreateByScrewing( PlSect, ptCen, vtAx, dAngRotDeg, dStepRotDeg, 0)) - return false ; - // aggiungo alla superficie complessiva - return ( pSTot->DoSewing( *pStm)) ; -} - -//------------------------------------------------------------------------------- -static bool -AddSurfJoint( ISurfTriMesh* pSTot, PolyLine& PlSect, const Vector3d& vtDirPrev, const ICurve* pCrv, const Vector3d& vtAx, double dLinTol) -{ - // direzione iniziale - Vector3d vtDir ; - pCrv->GetStartDir( vtDir) ; - // calcolo della rotazione - double dAngRotDeg ; - bool bDet ; - if ( vtDirPrev.GetRotation( vtDir, vtAx, dAngRotDeg, bDet) && abs( dAngRotDeg) > EPS_ANG_SMALL) { - Point3d ptCen ; - pCrv->GetStartPoint( ptCen) ; - // accodo la superficie di rivoluzione - if ( ! AddSurfRev( pSTot, PlSect, ptCen, vtAx, dAngRotDeg, dLinTol)) - return false ; - // aggiorno la posizione della sezione - PlSect.Rotate( ptCen, vtAx, dAngRotDeg) ; - } - return true ; -} - //------------------------------------------------------------------------------- ISurfTriMesh* GetSurfTriMeshSwept( const ICurve* pSect, const ICurve* pGuide, bool bCapEnds, double dLinTol) @@ -331,68 +301,101 @@ GetSurfTriMeshSwept( const ICurve* pSect, const ICurve* pGuide, bool bCapEnds, d // verifica parametri if ( pSect == nullptr || pGuide == nullptr) return nullptr ; + // verifico che la sezione sia piana + Plane3d plSect ; + if ( ! pSect->IsFlat( plSect, 10 * EPS_SMALL)) + return nullptr ; + // determino se la sezione è chiusa + bool bSectClosed = pSect->IsClosed() ; // calcolo la polilinea che approssima la sezione PolyLine PL ; if ( ! pSect->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL)) return nullptr ; // verifico che la linea guida sia piana - Plane3d plPlane ; - if ( ! pGuide->IsFlat( plPlane, 10 * EPS_SMALL)) + Plane3d plGuide ; + if ( ! pGuide->IsFlat( plGuide, 10 * EPS_SMALL)) return nullptr ; - // approssimo la linea guida con archi e rette - PolyArc PA ; - PtrOwner pGCo( CreateBasicCurveComposite()) ; - if ( IsNull( pGCo) || ! pGuide->ApproxWithArcs( dLinTol, ANG_TOL_STD_DEG, PA) || ! pGCo->FromPolyArc( PA)) - return nullptr ; - // creo e setto la superficie trimesh + // determino se la guida è chiusa + bool bGuideClosed = pGuide->IsClosed() ; + // riferimento all'inizio della linea guida + Frame3d frStart ; + Point3d ptStart ; + pGuide->GetStartPoint( ptStart) ; + Vector3d vtStart ; + pGuide->GetStartDir( vtStart) ; + Vector3d vtExtr = Z_AX ; + pGuide->GetExtrusion( vtExtr) ; + frStart.Set( ptStart, -vtStart, vtStart ^ vtExtr) ; + // porto la sezione in questo riferimento + if ( ! PL.ToLoc( frStart)) + return false ; + // calcolo la superficie PtrOwner pSTM( CreateSurfTriMesh()) ; if ( IsNull( pSTM)) - return nullptr ; - // per ogni tratto di linea guida eseguo estrusione o rotazione - Vector3d vtDirPrev ; - const ICurve* pCrv = pGCo->GetFirstCurve() ; - while ( pCrv != nullptr) { - // eventuale raccordo da precedente - if ( ! vtDirPrev.IsSmall()) { - if ( ! AddSurfJoint( pSTM, PL, vtDirPrev, pCrv, plPlane.GetVersN(), dLinTol)) - return nullptr ; - } - // se linea - if ( pCrv->GetType() == CRV_LINE) { - // creo superficie di estrusione - Vector3d vtExtr = GetCurveLine( pCrv)->GetEnd() - GetCurveLine( pCrv)->GetStart() ; - PtrOwner pSe( CreateSurfTriMesh()) ; - if ( IsNull( pSe) || ! pSe->CreateByExtrusion( PL, vtExtr)) - return nullptr ; - pSe->Invert() ; - // aggiungo alla superficie complessiva - pSTM->DoSewing( *pSe) ; - // aggiorno la posizione della sezione - PL.Translate( vtExtr) ; - } - // altrimenti arco - else { - // dati dell'arco - Point3d ptCen = GetCurveArc( pCrv)->GetCenter() ; - Vector3d vtAx = GetCurveArc( pCrv)->GetNormVersor() ; - double dAngRotDeg = GetCurveArc( pCrv)->GetAngCenter() ; - // accodo la superficie di rivoluzione - if ( ! AddSurfRev( pSTM, PL, ptCen, vtAx, dAngRotDeg, dLinTol)) - return nullptr ; - // aggiorno la posizione della sezione - PL.Rotate( ptCen, vtAx, dAngRotDeg) ; - } - // salvo direzione finale - pCrv->GetEndDir( vtDirPrev) ; - // passo alla successiva - pCrv = pGCo->GetNextCurve() ; - } - // se linea guida chiusa, eventuale raccordo tra ultimo e primo tratto - if ( pGCo->IsClosed()) { - if ( ! AddSurfJoint( pSTM, PL, vtDirPrev, pGCo->GetFirstCurve(), plPlane.GetVersN(), dLinTol)) + return false ; + // se richiesti caps, sezione chiusa e guida aperta, creo cap iniziale + if ( bCapEnds && bSectClosed && ! bGuideClosed) { + // creo e setto la superficie trimesh + PtrOwner pSc( CreateSurfTriMesh()) ; + if ( IsNull( pSc) || ! pSc->CreateByFlatContour( PL)) return nullptr ; + // la porto in globale + pSc->ToGlob( frStart) ; + // aggiungo alla superficie complessiva + pSTM->DoSewing( *pSc) ; } - + // superficie swept + PtrOwner pPrevCrv ; + Point3d ptP ; + bool bPoint = PL.GetFirstPoint( ptP) ; + while ( bPoint) { + // nuova curva + OffsetCurve OffsCrv ; + if ( ! OffsCrv.Make( pGuide, ptP.x, ICurve::OFF_FILLET) || OffsCrv.GetCurveCount() > 1) + return false ; + PtrOwner pCurrCrv( OffsCrv.GetLongerCurve()) ; + if ( IsNull( pCurrCrv)) + return false ; + pCurrCrv->Translate( ptP.y * frStart.VersY() + ptP.z * frStart.VersZ()) ; + // se esiste la curva precedente, costruisco la rigata (di tipo minima distanza) + if ( ! IsNull( pPrevCrv)) { + PtrOwner pSr( GetSurfTriMeshRuled( pPrevCrv, pCurrCrv, ISurfTriMesh::RLT_MINDIST, dLinTol)) ; + if ( IsNull( pSr)) + return false ; + pSTM->DoSewing( *pSr) ; + } + // salvo la curva come prossima precedente + pPrevCrv.Set( Release( pCurrCrv)) ; + // prossimo punto + bPoint = PL.GetNextPoint( ptP) ; + } + // se richiesti caps, sezione chiusa e guida aperta, creo cap finale + if ( bCapEnds && bSectClosed && ! bGuideClosed) { + // riferimento alla fine della linea guida + Frame3d frEnd ; + Point3d ptEnd ; + pGuide->GetEndPoint( ptEnd) ; + Vector3d vtEnd ; + pGuide->GetEndDir( vtEnd) ; + frEnd.Set( ptEnd, -vtEnd, vtEnd ^ vtExtr) ; + // creo e setto la superficie trimesh + PtrOwner pSc( CreateSurfTriMesh()) ; + if ( IsNull( pSc) || ! pSc->CreateByFlatContour( PL)) + return nullptr ; + // ne inverto la normale + pSc->Invert() ; + // la porto in globale + pSc->ToGlob( frEnd) ; + // aggiungo alla superficie complessiva + pSTM->DoSewing( *pSc) ; + } + // se superficie risultante chiusa, verifico che la normale sia verso l'esterno + double dVol ; + if ( pSTM->GetVolume( dVol) && dVol < 0) + pSTM->Invert() ; + // salvo tolleranza lineare usata + pSTM->SetLinearTolerance( dLinTol) ; + // restituisco la superficie return Release( pSTM) ; } @@ -419,7 +422,7 @@ GetSurfTriMeshRuled( const Point3d& ptP, const ICurve* pCurve, double dLinTol) //------------------------------------------------------------------------------- ISurfTriMesh* -GetSurfTriMeshRuled( const ICurve* pCurve1, const ICurve* pCurve2, double dLinTol) +GetSurfTriMeshRuled( const ICurve* pCurve1, const ICurve* pCurve2, int nType, double dLinTol) { // verifica parametri if ( pCurve1 == nullptr || pCurve2 == nullptr) @@ -434,7 +437,7 @@ GetSurfTriMeshRuled( const ICurve* pCurve1, const ICurve* pCurve2, double dLinTo return nullptr ; // creo e setto la superficie trimesh PtrOwner pSTM( CreateSurfTriMesh()) ; - if ( IsNull( pSTM) || ! pSTM->CreateByTwoCurves( PL1, PL2)) + if ( IsNull( pSTM) || ! pSTM->CreateByTwoCurves( PL1, PL2, nType)) return nullptr ; // salvo tolleranza lineare usata pSTM->SetLinearTolerance( dLinTol) ; diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index d688c4e..a6ef032 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -1861,170 +1861,344 @@ SurfTriMesh::CreateByPointCurve( const Point3d& ptP, const PolyLine& PL) //---------------------------------------------------------------------------- bool -SurfTriMesh::CreateByTwoCurves( const PolyLine& PL1, const PolyLine& PL2) +SurfTriMesh::CreateByTwoCurves( const PolyLine& PL1, const PolyLine& PL2, int nRuledType) { - // verifico validità polilinee (devono avere almeno 2 punti e non coincidere se non agli estremi aperti) - if ( ! VerifyPolylinesForTwoCurves( PL1, PL2)) - return false ; - // imposto ricalcolo m_nStatus = ERR ; m_OGrMgr.Reset() ; ResetHashGrids3d() ; - // 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 nVertNbr = PL1.GetPointNbr() + PL2.GetPointNbr() ; - int nTriaNbr = max( PL1.GetPointNbr(), PL2.GetPointNbr()) + 1 ; - if ( ! Init( nVertNbr, nTriaNbr)) - 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] ; - // se i punti iniziali non coincidono, inserisco il vertice iniziale di 2 - if ( ! AreSamePointApprox( ptP1p, ptP2p)) { - if ( ( nV2p = AddVertex( ptP2p)) == SVT_NULL) + // se rigata a minima distanza tra le due curve + if ( nRuledType == RLT_MINDIST) { + // verifico ci siano almeno due punti diversi per curva + if ( ( PL1.IsClosed() && PL1.GetPointNbr() < 3) || PL1.GetPointNbr() < 2) return false ; + if ( ( PL2.IsClosed() && PL2.GetPointNbr() < 3) || PL2.GetPointNbr() < 2) + return false ; + + // flag di curve entrambe chiuse e correzione conseguente a numero totale punti differenti + bool bClosed = PL1.IsClosed() && PL2.IsClosed() ; + + // vettori punti con primo punto dell'altra curva a distanza minima + PNTUVECTOR vPnt1 ; + vPnt1.reserve( PL1.GetPointNbr()) ; + Point3d ptP1 ; + bool bF1 = PL1.GetFirstPoint( ptP1) ; + while ( bF1) { + vPnt1.emplace_back( ptP1, -1) ; + bF1 = PL1.GetNextPoint( ptP1) ; + } + int nTotP1 = int( vPnt1.size()) ; + PNTUVECTOR vPnt2 ; + vPnt2.reserve( PL2.GetPointNbr()) ; + Point3d ptP2 ; + bool bF2 = PL2.GetFirstPoint( ptP2) ; + while ( bF2) { + vPnt2.emplace_back( ptP2, -1) ; + bF2 = PL2.GetNextPoint( ptP2) ; + } + int nTotP2 = int( vPnt2.size()) ; + // calcoli per prima curva + int LastJ = 0 ; + vPnt1[0].second = 0 ; + for ( int i = 1 ; i < nTotP1 ; ++ i) { + double dSqDistMin = SqDist( vPnt1[i].first, vPnt2[LastJ].first) ; + double dApprDistMin = ApproxDist( vPnt1[i].first, vPnt2[LastJ].first) ; + int MinJ = LastJ ; + for ( int j = LastJ + 1 ; j < nTotP2 ; ++ j) { + double dSqDist = SqDist( vPnt1[i].first, vPnt2[j].first) ; + if ( dSqDist < dSqDistMin - 2 * dApprDistMin * EPS_SMALL) { + dSqDistMin = dSqDist ; + dApprDistMin = ApproxDist( vPnt1[i].first, vPnt2[j].first) ; + MinJ = j ; + } + else if ( dSqDist > 16 * dSqDistMin) + break ; + } + if ( i < nTotP1 - 1 && dSqDistMin < EPS_SMALL) + return false ; + vPnt1[i].second = MinJ ; + LastJ = MinJ ; + } + // calcoli per seconda curva + int LastI = 0 ; + vPnt2[0].second = 0 ; + for ( int j = 1 ; j < nTotP2 ; ++ j) { + double dSqDistMin = SqDist( vPnt2[j].first, vPnt1[LastI].first) ; + double dApprDistMin = ApproxDist( vPnt2[j].first, vPnt1[LastI].first) ; + int MinI = LastI ; + for ( int i = LastI + 1 ; i < nTotP1 ; ++ i) { + double dSqDist = SqDist( vPnt2[j].first, vPnt1[i].first) ; + if ( dSqDist < dSqDistMin - 2 * dApprDistMin * EPS_SMALL) { + dSqDistMin = dSqDist ; + dApprDistMin = ApproxDist( vPnt2[j].first, vPnt1[i].first) ; + MinI = i ; + } + else if ( dSqDist > 16 * dSqDistMin) + break ; + } + if ( j < nTotP2 - 1 && dSqDistMin < EPS_SMALL) + return false ; + vPnt2[j].second = MinI ; + LastI = MinI ; + } + + // Costruisco la mesh + int nVertNbr = nTotP1 + nTotP2 ; + int nTriaNbr = max( nTotP1, nTotP2) + 1 ; + if ( ! Init( nVertNbr, nTriaNbr)) + return false ; + + // Recupero i punti iniziali sulla curva 1 + int nV1p ; int nP1p = 0 ; + int nV1s ; int nP1s = 1 ; + bool bNext1 = ( nP1s < nTotP1) ; + if ( ! bNext1) + return false ; + if ( ( nV1p = AddVertex( vPnt1[nP1p].first)) == SVT_NULL) + return false ; + // Recupero i punti iniziali sulla curva 2 + int nV2p ; int nP2p = 0 ; + int nV2s ; int nP2s = 1 ; + bool bNext2 = ( nP2s < nTotP2) ; + if ( ! bNext2) + return false ; + int nIdV[3] ; + // se i punti iniziali non coincidono, inserisco il vertice iniziale di 2 + if ( ! AreSamePointApprox( vPnt1[nP1p].first, vPnt2[nP2p].first)) { + if ( ( nV2p = AddVertex( vPnt2[nP2p].first)) == SVT_NULL) + return false ; + } + // altrimenti, inserisco un triangolo e mi sposto in avanti su entrambe le curve + else { + // inserisco il vertice V1s + if ( ( nV1s = AddVertex( vPnt1[nP1s].first)) == SVT_NULL) + return false ; + // inserisco il vertice V2s + if ( ( nV2s = AddVertex( vPnt2[nP2s].first)) == SVT_NULL) + return false ; + // inserisco il triangolo V1p -> V1s -> V2s + nIdV[0] = nV1p ; + nIdV[1] = nV1s ; + nIdV[2] = nV2s ; + if ( AddTriangle( nIdV) == SVT_NULL) + return false ; + // passo al punto successivo su 1 + nV1p = nV1s ; nP1p = nP1s ; ++ nP1s ; + bNext1 = ( nP1s < nTotP1) ; + // passo al punto successivo su 2 + nV2p = nV2s ; nP2p = nP2s ; ++ nP2s ; + bNext2 = ( nP2s < nTotP2) ; + } + // ciclo sui punti + while ( bNext1 || bNext2) { + // se c'è nuovo V1s e la diagonale più corta è V2p -> V1s oppure non c'è V2s + if ( ! bNext2 || ( bNext1 && ( nP1s == vPnt2[nP2p].second || vPnt1[nP1s].second == nP2p))) { + // inserisco il vertice V1s (se ultimo e curve chiuse, prendo il primo) + if ( nP1s == nTotP1 - 1 && bClosed) + nV1s = 0 ; + else if ( ( nV1s = AddVertex( vPnt1[nP1s].first)) == SVT_NULL) + return false ; + // inserisco il triangolo V2p -> V1p -> V1s + nIdV[0] = nV2p ; + nIdV[1] = nV1p ; + nIdV[2] = nV1s ; + if ( AddTriangle( nIdV) == SVT_NULL) + return false ; + // se i punti correnti coincidono passo al successivo anche su 2 + if ( bNext2 && AreSamePointApprox( vPnt1[nP1s].first, vPnt2[nP2s].first)) { + nV2p = nV2s ; nP2p = nP2s ; ++ nP2s ; + bNext2 = ( nP2s < nTotP2) ; + } + // passo al punto successivo su 1 + nV1p = nV1s ; nP1p = nP1s ; ++ nP1s ; + bNext1 = ( nP1s < nTotP1) ; + } + // altrimenti è V1p -> V2s + else { + // inserisco il vertice V2s (se ultimo e curve chiuse, prendo il primo) + if ( nP2s == nTotP2 - 1 && bClosed) + nV2s = 1 ; + else if ( ( nV2s = AddVertex( vPnt2[nP2s].first)) == SVT_NULL) + return false ; + // inserisco il triangolo V2p -> V1p -> V2s + 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 ( bNext1 && AreSamePointApprox( vPnt1[nP1s].first, vPnt2[nP2s].first)) { + nV1p = nV1s ; nP1p = nP1s ; ++ nP1s ; + bNext1 = ( nP1s < nTotP1) ; + } + // passo al punto successivo su 2 + nV2p = nV2s ; nP2p = nP2s ; ++ nP2s ; + bNext2 = ( nP2s < nTotP2) ; + } + } } - // altrimenti, inserisco un triangolo e mi sposto in avanti su entrambe le curve + + // altrimenti rigata con parametrizzazione sincrona sulle due curve else { - // inserisco il vertice A1s - if ( ( nV1s = AddVertex( ptP1s)) == SVT_NULL) + // verifico validità polilinee (devono avere almeno 2 punti e non coincidere se non agli estremi aperti) + if ( ! VerifyPolylinesForTwoCurves( PL1, PL2)) return false ; - // inserisco il vertice A2s - if ( ( nV2s = AddVertex( ptP2s)) == SVT_NULL) + + // 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 ; - // inserisco il triangolo A1p -> A1s -> A2s - nIdV[0] = nV1p ; - nIdV[1] = nV1s ; - nIdV[2] = nV2s ; - if ( AddTriangle( nIdV) == SVT_NULL) + double dU2F ; PL2.GetFirstU( dU2F) ; + double dU2L ; PL2.GetLastU( dU2L) ; + double dDeltaU2 = dU2L - dU2F ; + if ( dDeltaU2 < EPS_SMALL) 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 c'è nuovo dA1s e la diagonale più corta è dA2p -> dA1s oppure non c'è dA2s - if ( ( bNext1 && ( dA1s - dA2p) <= ( dA2s - dA1p) + EPS_PARAM) || ! bNext2) { + + // costruisco la mesh + int nVertNbr = PL1.GetPointNbr() + PL2.GetPointNbr() ; + int nTriaNbr = max( PL1.GetPointNbr(), PL2.GetPointNbr()) + 1 ; + if ( ! Init( nVertNbr, nTriaNbr)) + 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] ; + // se i punti iniziali non coincidono, inserisco il vertice iniziale di 2 + if ( ! AreSamePointApprox( 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 triangolo A2p -> A1p -> A1s - nIdV[0] = nV2p ; - nIdV[1] = nV1p ; - nIdV[2] = nV1s ; + // 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 ; - // se i punti correnti coincidono passo al successivo anche su 2 - if ( AreSamePointApprox( 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 ; + // 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 ; } - // 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 ( AreSamePointApprox( ptP1s, ptP2s)) { + // ciclo sui punti + while ( bNext1 || bNext2) { + // se c'è nuovo dA1s e la diagonale più corta è dA2p -> dA1s oppure non c'è dA2s + if ( ( bNext1 && ( dA1s - dA2p) <= ( dA2s - dA1p) + EPS_PARAM) || ! bNext2) { + // inserisco il vertice A1s + if ( ( nV1s = AddVertex( ptP1s)) == SVT_NULL) + return false ; + // inserisco il triangolo A2p -> A1p -> A1s + nIdV[0] = nV2p ; + nIdV[1] = nV1p ; + nIdV[2] = nV1s ; + if ( AddTriangle( nIdV) == SVT_NULL) + return false ; + // se i punti correnti coincidono passo al successivo anche su 2 + if ( AreSamePointApprox( 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 ; } - // 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 ; + // 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 ( AreSamePointApprox( 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 è dA1p -> dA2s = 1 - else { - // inserisco il triangolo A2p -> A1p -> A2s = 1 - nIdV[0] = nV2p ; - nIdV[1] = nV1p ; - nIdV[2] = 1 ; - if ( AddTriangle( nIdV) == SVT_NULL) - return false ; - // inserisco il triangolo A1p -> A1s = 0 -> A2s = 1 - nIdV[0] = nV1p ; - nIdV[1] = 0 ; - nIdV[2] = 1 ; - if ( AddTriangle( nIdV) == SVT_NULL) - return false ; + // 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 è dA1p -> dA2s = 1 + else { + // inserisco il triangolo A2p -> A1p -> A2s = 1 + nIdV[0] = nV2p ; + nIdV[1] = nV1p ; + nIdV[2] = 1 ; + if ( AddTriangle( nIdV) == SVT_NULL) + return false ; + // inserisco il triangolo A1p -> A1s = 0 -> A2s = 1 + nIdV[0] = nV1p ; + nIdV[1] = 0 ; + nIdV[2] = 1 ; + if ( AddTriangle( nIdV) == SVT_NULL) + return false ; + } } } @@ -2117,6 +2291,115 @@ SurfTriMesh::CreateByRevolution( const PolyLine& PL, const Point3d& ptAx, const return CreateByScrewing( PL, ptAx, vtAx, dAngRot, dStepRot, 0) ; } +//---------------------------------------------------------------------------- +static bool +VeryfyPolylineForRevolution( const PolyLine& PL, const Point3d& ptAx, const Vector3d& vtAx) +{ + // calcolo un riferimento con origine ptAx e asseZ vtAx + Frame3d frAx ; + if ( ! frAx.Set( ptAx, vtAx)) + return false ; + + // numero di segmenti della polilinea + int nTotSeg = PL.GetLineNbr() ; + // flag di chiusa + bool bClosed = PL.IsClosed() ; + + // recupero il primo punto e lo porto nel riferimento Ax e quindi lo proietto su XY + Point3d ptPp ; + if ( ! PL.GetFirstPoint( ptPp)) + return false ; + ptPp.ToLoc( frAx) ; + ptPp.z = 0 ; + + // calcolo la distanza tra i segmenti della polilinea portati nel piano XY del rif Ax e l'origine + int nSeg = 0 ; + Point3d ptPc ; + while ( PL.GetNextPoint( ptPc)) { + // punto corrente + ptPc.ToLoc( frAx) ; + ptPc.z = 0 ; + ++ nSeg ; + // verifico distanza + if ( DistPointLine( ORIG, ptPp, ptPc).IsSmall()) { + if ( bClosed || + ( ! ( nSeg == 1 && AreSamePointApprox( ORIG, ptPp)) && + ! ( nSeg == nTotSeg && AreSamePointApprox( ORIG, ptPc)))) + return false ; + } + // salvo punto + ptPp = ptPc ; + } + return true ; +} + +//---------------------------------------------------------------------------- +static bool +AdjustPolylineForRevolution( PolyLine& PL, const Point3d& ptAx, const Vector3d& vtAx) +{ + Vector3d vtAxN = vtAx ; + vtAxN.Normalize() ; + // determino il piano della polilinea + int nRank ; + Point3d ptCen ; + Vector3d vtScN ; + if ( ! PL.IsFlat( nRank, ptCen, vtScN, 10 * EPS_SMALL) || nRank == 0) + return false ; + Plane3d plSect ; + if ( nRank >= 2) + plSect.Set( ptCen, vtScN) ; + else { + if ( ! plSect.Set( ptCen, vtAxN ^ vtScN)) + return false ; + } + + // verifico che l'asse giaccia nel piano + if ( ! PointInPlaneApprox( ptAx, plSect) || ! PointInPlaneApprox( ptAx + 100 * vtAxN, plSect)) + return false ; + + // calcolo il piano perpendicolare a quello della curva e contenente l'asse + Vector3d vtTrN = ( ptCen - ptAx) - ( ptCen - ptAx) * vtAxN * vtAxN ; + if ( ! vtTrN.Normalize()) { + vtTrN = vtAxN ^ vtScN ; + vtTrN.Normalize() ; + } + Plane3d plTrim ; + plTrim.Set( ptAx, vtTrN) ; + + // Trimmo la polilinea con il piano (leggermente spostato) + const double DIST_SIC = 5 * EPS_SMALL ; + plTrim.Translate( DIST_SIC * vtTrN) ; + PL.Trim( plTrim, false) ; + + // Se polilinea risultante è aperta con estremità molto vicine all'asse le porto su questo + if ( ! PL.IsClosed()) { + // verifico l'inizio + double dUStart ; + Point3d ptStart ; + PL.GetFirstUPoint( &dUStart, &ptStart) ; + DistPointLine dStAx( ptStart, ptAx, vtAx, 1, false) ; + double dStDist ; + if ( dStAx.GetDist( dStDist) && dStDist < 1.1 * DIST_SIC) { + dStAx.GetMinDistPoint( ptStart) ; + PL.EraseFirstUPoint() ; + PL.AddUPoint( dUStart, ptStart, false) ; + } + // verifico la fine + double dUEnd ; + Point3d ptEnd ; + PL.GetLastUPoint( &dUEnd, &ptEnd) ; + DistPointLine dEnAx( ptEnd, ptAx, vtAx, 1, false) ; + double dEnDist ; + if ( dEnAx.GetDist( dEnDist) && dEnDist < 1.1 * DIST_SIC) { + dEnAx.GetMinDistPoint( ptEnd) ; + PL.EraseLastUPoint() ; + PL.AddUPoint( dUEnd, ptEnd, true) ; + } + } + + return true ; +} + //---------------------------------------------------------------------------- bool SurfTriMesh::CreateByScrewing( const PolyLine& PL, const Point3d& ptAx, const Vector3d& vtAx, @@ -2155,7 +2438,8 @@ SurfTriMesh::CreateByScrewing( const PolyLine& PL, const Point3d& ptAx, const Ve -- nStep ; // verifico che la polilinea non attraversi l'asse di rivoluzione o lo tocchi in punti interni - if ( ! VeryfyPolylineForRevolution( PL, ptAx, vtAx)) { + PolyLine MyPL = PL ; + if ( ! VeryfyPolylineForRevolution( MyPL, ptAx, vtAx) && ! AdjustPolylineForRevolution( MyPL, ptAx, vtAx)) { LOG_ERROR( GetEGkLogger(), "StmCreateByRevolution : polyline inside meets axis") return false ; } @@ -2166,10 +2450,10 @@ SurfTriMesh::CreateByScrewing( const PolyLine& PL, const Point3d& ptAx, const Ve ResetHashGrids3d() ; // verifico se la polilinea è chiusa - bool bClosed = PL.IsClosed() ; + bool bClosed = MyPL.IsClosed() ; // costruisco la mesh - int nPointNbr = PL.GetPointNbr() ; + int nPointNbr = MyPL.GetPointNbr() ; if ( ! Init( ( 1 + nStep) * nPointNbr, ( 1 + nStep) * nPointNbr)) return false ; @@ -2177,7 +2461,7 @@ SurfTriMesh::CreateByScrewing( const PolyLine& PL, const Point3d& ptAx, const Ve int nV = -1 ; Point3d ptP ; // recupero il punto - if ( ! PL.GetFirstPoint( ptP)) + if ( ! MyPL.GetFirstPoint( ptP)) return false ; // inserisco il primo vertice if ( AddVertex( ptP) == SVT_NULL) @@ -2199,7 +2483,7 @@ SurfTriMesh::CreateByScrewing( const PolyLine& PL, const Point3d& ptAx, const Ve } // ciclo sui punti della polilinea (per inserire vertice e suoi ruotati + 2 triangoli per ogni punto) int nIdV[4] ; - while ( PL.GetNextPoint( ptP, bClosed)) { + while ( MyPL.GetNextPoint( ptP, bClosed)) { // aggiungo il primo vertice if ( AddVertex( ptP) == SVT_NULL) return false ; @@ -2306,48 +2590,6 @@ SurfTriMesh::CreateByScrewing( const PolyLine& PL, const Point3d& ptAx, const Ve return AdjustTopology() ; } -//---------------------------------------------------------------------------- -bool -SurfTriMesh::VeryfyPolylineForRevolution( const PolyLine& PL, const Point3d& ptAx, const Vector3d& vtAx) const -{ - // calcolo un riferimento con origine ptAx e asseZ vtAx - Frame3d frAx ; - if ( ! frAx.Set( ptAx, vtAx)) - return false ; - - // numero di segmenti della polilinea - int nTotSeg = PL.GetLineNbr() ; - // flag di chiusa - bool bClosed = PL.IsClosed() ; - - // recupero il primo punto e lo porto nel riferimento Ax e quindi lo proietto su XY - Point3d ptPp ; - if ( ! PL.GetFirstPoint( ptPp)) - return false ; - ptPp.ToLoc( frAx) ; - ptPp.z = 0 ; - - // calcolo la distanza tra i segmenti della polilinea portati nel piano XY del rif Ax e l'origine - int nSeg = 0 ; - Point3d ptPc ; - while ( PL.GetNextPoint( ptPc)) { - // punto corrente - ptPc.ToLoc( frAx) ; - ptPc.z = 0 ; - ++ nSeg ; - // verifico distanza - if ( DistPointLine( ORIG, ptPp, ptPc).IsSmall()) { - if ( bClosed || - ( ! ( nSeg == 1 && AreSamePointApprox( ORIG, ptPp)) && - ! ( nSeg == nTotSeg && AreSamePointApprox( ORIG, ptPc)))) - return false ; - } - // salvo punto - ptPp = ptPc ; - } - return true ; -} - //---------------------------------------------------------------------------- bool SurfTriMesh::AddBiTriangle( const int nIdVert[4]) diff --git a/SurfTriMesh.h b/SurfTriMesh.h index 37fc9b3..10f510f 100644 --- a/SurfTriMesh.h +++ b/SurfTriMesh.h @@ -135,7 +135,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW bool CreateByRegion( const POLYLINEVECTOR& vPL) override ; bool CreateByExtrusion( const PolyLine& PL, const Vector3d& vtExtr) override ; bool CreateByPointCurve( const Point3d& ptP, const PolyLine& PL) override ; - bool CreateByTwoCurves( const PolyLine& PL1, const PolyLine& PL2) override ; + bool CreateByTwoCurves( const PolyLine& PL1, const PolyLine& PL2, int nRuledType) override ; bool CreateByRevolution( const PolyLine& PL, const Point3d& ptAx, const Vector3d& vtAx, double dAngRot, double dStepRot) override ; bool CreateByScrewing( const PolyLine& PL, const Point3d& ptAx, const Vector3d& vtAx, @@ -239,7 +239,6 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW bool MarchAlongLoop( int nT, int nV, int nTimeStamp, PolyLine& PL) const ; bool MarchOneTria( int& nT, int& nV, int nTimeStamp, PolyLine& PL, bool& bEnd) 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 ResetFaceting( void) ; bool VerifyFaceting( void) const ;