//---------------------------------------------------------------------------- // EgalTech 2015-2015 //---------------------------------------------------------------------------- // File : StmFromCurves.cpp Data : 01.02.15 Versione : 1.6b1 // Contenuto : Implementazione di funzioni per creazione di superfici Stm // a partire da curve, con diversi metodi. // // // Modifiche : 01.02.15 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "GeoConst.h" #include "/EgtDev/Include/EGkStmFromCurves.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include using namespace std ; //------------------------------------------------------------------------------- static bool CalcRegionPolyLines( const ICURVEPVECTOR& vpCurve, double dLinTol, POLYLINEVECTOR& vPL, Vector3d& vtN) ; //------------------------------------------------------------------------------- ISurfTriMesh* GetSurfTriMeshByFlatContour( const ICurve* pCurve, double dLinTol) { // verifica parametri if ( pCurve == nullptr) return nullptr ; // calcolo la polilinea che approssima la curva PolyLine PL ; if ( ! pCurve->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL)) return nullptr ; // creo e setto la superficie trimesh PtrOwner pSTM( CreateSurfTriMesh()) ; if ( IsNull( pSTM) || ! pSTM->CreateByFlatContour( PL)) return nullptr ; // restituisco la superficie return Release( pSTM) ; } //------------------------------------------------------------------------------- ISurfTriMesh* 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 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 ( pCurve == nullptr || &vtExtr == nullptr) return nullptr ; // calcolo la polilinea che approssima la curva PolyLine PL ; if ( ! pCurve->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL)) return nullptr ; // se richiesta chiusura agli estremi bool bDoCapEnds = false ; if ( bCapEnds) { // verifico che la curva sia chiusa e piatta Plane3d plPlane ; double dArea ; if ( PL.IsClosedAndFlat( plPlane, dArea, 50 * EPS_SMALL)) { // componente dell'estrusione perpendicolare al piano della curva double dOrthoExtr = plPlane.vtN * vtExtr ; if ( ( fabs( dOrthoExtr) > EPS_SMALL)) { bDoCapEnds = true ; // se negativa, inverto il senso del contorno if ( dOrthoExtr < 0) PL.Invert() ; } } } // creo e setto la superficie trimesh PtrOwner pSTM( CreateSurfTriMesh()) ; if ( IsNull( pSTM) || ! pSTM->CreateByExtrusion( PL, vtExtr)) return nullptr ; // se da fare, metto i tappi sulle estremità if ( bDoCapEnds) { // creo la prima superficie di estremità PtrOwner pSTM1( CreateSurfTriMesh()) ; if ( IsNull( pSTM1) || ! pSTM1->CreateByFlatContour( PL)) return nullptr ; // la copio PtrOwner pSTM2( GetSurfTriMesh( pSTM1->Clone())) ; if ( IsNull( pSTM2)) return nullptr ; // inverto la prima superficie pSTM1->Invert() ; // traslo la seconda pSTM2->Translate( vtExtr) ; // le unisco alla superficie del fianco if ( ! pSTM->DoSewing( *pSTM1) || ! pSTM->DoSewing( *pSTM2)) return nullptr ; } // restituisco la superficie return Release( pSTM) ; } //------------------------------------------------------------------------------- ISurfTriMesh* 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 pSTM( CreateSurfTriMesh()) ; if ( IsNull( pSTM) || ! pSTM->CreateByRegion( vPL)) return nullptr ; // creo la seconda superficie e la unisco alla prima { // copio la prima superficie PtrOwner 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 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 ( 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 ( ! pCurve->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL)) return nullptr ; // calcolo lo step di rotazione double dMaxRad = 0 ; if ( ! PL.GetMaxDistanceFromLine( dMaxRad, ptAx, vtAx, 1, false) || dMaxRad < EPS_SMALL) return nullptr ; double dStepRotDeg = sqrt( 8 * dLinTol / dMaxRad) * RADTODEG ; // se richiesta chiusura degli estremi if ( bCapEnds && ! PL.IsClosed()) { Vector3d vtAxN = vtAx ; vtAxN.Normalize() ; double dPosIni, dPosFin ; Point3d ptP ; // proietto l'ultimo punto sull'asse di rotazione if ( PL.GetLastPoint( ptP)) { dPosFin = ( ptP - ptAx) * vtAxN ; Point3d ptPOnAx = ptAx + dPosFin * vtAxN ; // se non giace sull'asse, aggiungo il punto proiettato if ( ! AreSamePointApprox( ptP, ptPOnAx)) { double dU ; PL.GetLastU( dU) ; PL.AddUPoint( ( dU + 1), ptPOnAx) ; } } // inverto la polilinea PL.Invert() ; // proietto l'ultimo punto (era il primo) sull'asse di rotazione if ( PL.GetLastPoint( ptP)) { dPosIni = ( ptP - ptAx) * vtAxN ; Point3d ptPOnAx = ptAx + dPosIni * vtAxN ; // se non giace sull'asse, aggiungo il punto proiettato if ( ! AreSamePointApprox( ptP, ptPOnAx)) { double dU ; PL.GetLastU( dU) ; PL.AddUPoint( ( dU + 1), ptPOnAx) ; } } // decido se reinvertire la polilinea if ( dPosFin > dPosIni) PL.Invert() ; } // creo e setto la superficie trimesh PtrOwner pSTM( CreateSurfTriMesh()) ; if ( IsNull( pSTM) || ! pSTM->CreateByScrewing( PL, ptAx, vtAx, ANG_FULL, dStepRotDeg, 0)) return nullptr ; // restituisco la superficie return Release( pSTM) ; } //------------------------------------------------------------------------------- ISurfTriMesh* GetSurfTriMeshByScrewing( const ICurve* pCurve, const Point3d& ptAx, const Vector3d& vtAx, double dAngRotDeg, double dMove, double dLinTol) { // verifica parametri 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 ( ! pCurve->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL)) return nullptr ; // calcolo lo step di rotazione double dMaxRad = 0 ; if ( ! PL.GetMaxDistanceFromLine( dMaxRad, ptAx, vtAx, 1, false) || dMaxRad < EPS_SMALL) return nullptr ; double dStepRotDeg = sqrt( 8 * dLinTol / dMaxRad) * RADTODEG ; // se superficie rototraslata, necessari limiti sulla lunghezza dei segmenti if ( fabs( dAngRotDeg) > EPS_ANG_SMALL && fabs( dMove) > EPS_SMALL){ double dLenMax = 2.5 * fabs( dMove * dStepRotDeg / dAngRotDeg) ; if ( ! PL.AdjustForMaxSegmentLen( dLenMax)) return nullptr ; } // creo e setto la superficie trimesh PtrOwner pSTM( CreateSurfTriMesh()) ; if ( IsNull( pSTM) || ! pSTM->CreateByScrewing( PL, ptAx, vtAx, dAngRotDeg, dStepRotDeg, dMove)) return nullptr ; // restituisco la superficie return Release( pSTM) ; } //------------------------------------------------------------------------------- ISurfTriMesh* GetSurfTriMeshRuled( const ICurve* pCurve1, const ICurve* pCurve2, double dLinTol) { // verifica parametri if ( pCurve1 == nullptr || pCurve2 == nullptr) return nullptr ; // calcolo la polilinea che approssima la prima curva PolyLine PL1 ; if ( ! pCurve1->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL1)) return nullptr ; // calcolo la polilinea che approssima la seconda curva PolyLine PL2 ; if ( ! pCurve2->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL2)) return nullptr ; // creo e setto la superficie trimesh PtrOwner pSTM( CreateSurfTriMesh()) ; if ( IsNull( pSTM) || ! pSTM->CreateByTwoCurves( PL1, PL2)) return nullptr ; // 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 INDAREA ; // coppia indice, area typedef std::vector 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 ; }