diff --git a/CurveArc.cpp b/CurveArc.cpp index 43db995..df25b04 100644 --- a/CurveArc.cpp +++ b/CurveArc.cpp @@ -402,6 +402,14 @@ CurveArc::GetLength( double& dLen) const bool CurveArc::ApproxWithLines( double dLinTol, double dAngTolDeg, PolyLine& PL) const { + // pulisco la polilinea + PL.Clear() ; + + // la curva deve essere validata + if ( m_nStatus != OK) + return false ; + + // eseguo approssimazione ArcApproxer aAppr( dLinTol, dAngTolDeg, true, *this) ; double dU ; Point3d ptPos ; diff --git a/CurveBezier.cpp b/CurveBezier.cpp index 55635e6..2ca595b 100644 --- a/CurveBezier.cpp +++ b/CurveBezier.cpp @@ -1133,6 +1133,9 @@ CurveBezier::FlatOrSplit( int nLev, const CurveBezier& crvBez, double dParStart, bool CurveBezier::ApproxWithLines( double dLinTol, double dAngTolDeg, PolyLine& PL) const { + // pulisco la polilinea + PL.Clear() ; + // la curva deve essere validata if ( m_nStatus != OK) return false ; diff --git a/CurveComposite.cpp b/CurveComposite.cpp index 546c30f..c529e3a 100644 --- a/CurveComposite.cpp +++ b/CurveComposite.cpp @@ -536,15 +536,18 @@ CurveComposite::GetLength( double& dLen) const bool CurveComposite::ApproxWithLines( double dLinTol, double dAngTolDeg, PolyLine& PL) const { - bool bFirst ; - double dStartPar ; - Point3d ptP ; + // pulisco la polilinea + PL.Clear() ; + + // la curva deve essere validata + if ( m_nStatus != OK) + return false ; + + // eseguo approssimazione + bool bFirst = true ; + double dStartPar = 0 ; PolyLine PLSmpl ; PCRVSMPL_LIST::const_iterator Iter ; - - - bFirst = true ; - dStartPar = 0 ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) { // recupero approssimazione per curva semplice if ( ! (*Iter)->ApproxWithLines( dLinTol, dAngTolDeg, PLSmpl)) diff --git a/CurveLine.cpp b/CurveLine.cpp index 03a9044..518ab6b 100644 --- a/CurveLine.cpp +++ b/CurveLine.cpp @@ -264,6 +264,9 @@ CurveLine::GetLength( double& dLen) const bool CurveLine::ApproxWithLines( double dLinTol, double dAngTolDeg, PolyLine& PL) const { + // pulisco la polilinea + PL.Clear() ; + // la curva deve essere validata if ( m_nStatus != OK) return false ; diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 4403278..d3db20e 100644 Binary files a/EgtGeomKernel.rc and b/EgtGeomKernel.rc differ diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj index cb532af..27e99bd 100644 --- a/EgtGeomKernel.vcxproj +++ b/EgtGeomKernel.vcxproj @@ -264,6 +264,7 @@ copy $(TargetPath) \EgtProg\Dll64 + @@ -290,6 +291,7 @@ copy $(TargetPath) \EgtProg\Dll64 + @@ -337,6 +339,7 @@ copy $(TargetPath) \EgtProg\Dll64 + diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index fa22283..56eca04 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -138,6 +138,9 @@ File di origine\Geo + + File di origine\Base + @@ -350,6 +353,12 @@ File di intestazione + + File di intestazione + + + File di intestazione + diff --git a/GdbExecutor.cpp b/GdbExecutor.cpp index 0af297f..1f1bc4c 100644 --- a/GdbExecutor.cpp +++ b/GdbExecutor.cpp @@ -100,6 +100,8 @@ GdbExecutor::GdbExecutor( void) m_ExecMgr.Insert( "MIRROR", &GdbExecutor::ExecuteMirror) ; m_ExecMgr.Insert( "INVC", &GdbExecutor::ExecuteInvertCurve) ; m_ExecMgr.Insert( "INVERTCURVE", &GdbExecutor::ExecuteInvertCurve) ; + m_ExecMgr.Insert( "INVS", &GdbExecutor::ExecuteInvertSurf) ; + m_ExecMgr.Insert( "INVERTSURF", &GdbExecutor::ExecuteInvertSurf) ; m_ExecMgr.Insert( "TRC", &GdbExecutor::ExecuteTrimCurve) ; m_ExecMgr.Insert( "TRIMCURVE", &GdbExecutor::ExecuteTrimCurve) ; m_ExecMgr.Insert( "NEW", &GdbExecutor::ExecuteNew) ; @@ -697,6 +699,7 @@ GdbExecutor::ExecuteCurveCompo( const string& sCmd2, const STRVECTOR& vsParams) bool GdbExecutor::ExecuteSurfTriMesh( const string& sCmd2, const STRVECTOR& vsParams) { + // se inizio creazione con componenti elementari if ( sCmd2 == "BEGIN") { // 2 parametri opzionali : numero vertici e numero triangoli if ( vsParams.size() > 2) @@ -719,6 +722,7 @@ GdbExecutor::ExecuteSurfTriMesh( const string& sCmd2, const STRVECTOR& vsParams) m_pGeoObj = pSTM ; return true ; } + // se nuovo vertice else if ( sCmd2 == "VERT" || sCmd2 == "ADDVERTEX") { // 1 parametro : punto if ( vsParams.size() != 1) @@ -734,6 +738,7 @@ GdbExecutor::ExecuteSurfTriMesh( const string& sCmd2, const STRVECTOR& vsParams) // aggiungo il vertice return ( pSTM->AddVertex( ptP) != -1) ; } + // se nuovo triangolo else if ( sCmd2 == "TRIA" || sCmd2 == "ADDTRIANGLE") { // 3 parametri : IdV1, IdV2, IdV3 if ( vsParams.size() != 3) @@ -751,6 +756,7 @@ GdbExecutor::ExecuteSurfTriMesh( const string& sCmd2, const STRVECTOR& vsParams) // aggiungo il triangolo definito con gli indici dei 3 vertici return ( pSTM->AddTriangle( nIdVert) != -1) ; } + // se fine creazione else if ( sCmd2 == "END") { // 2 parametri : Id e ParentId if ( vsParams.size() != 2) @@ -766,6 +772,108 @@ GdbExecutor::ExecuteSurfTriMesh( const string& sCmd2, const STRVECTOR& vsParams) m_pGeoObj = nullptr ; return AddGeoObj( vsParams[0], vsParams[1], pSTM) ; } + // se creazione per triangolazione di un contorno chiuso e piano + else if ( sCmd2 == "CONT" || sCmd2 == "BYCONTOUR") { + // 3 parametri : Id, ParentId, IdCurve + if ( vsParams.size() != 3) + return false ; + // 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( 0.01, 15, 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 ( ! pCrv->ApproxWithLines( 0.01, 15, PL)) + return false ; + } + // creo la superficie + PtrOwner pSTM( CreateSurfTriMesh()) ; + if ( ! IsValid( pSTM)) + return false ; + // costruisco la triangolazione + if ( ! pSTM->CreateByTriangulation( PL)) + return false ; + // inserisco la superficie trimesh nel DB + return AddGeoObj( vsParams[0], vsParams[1], Release( pSTM)) ; + } + // se creazione per estrusione + else if ( sCmd2 == "EXTR" || sCmd2 == "BYEXTRUSION") { + // 4 parametri : Id, ParentId, IdCurve, vtExtr + if ( vsParams.size() != 4) + return false ; + // 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( 0.01, 15, 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 ( ! pCrv->ApproxWithLines( 0.01, 15, PL)) + return false ; + } + // recupero il vettore di estrusione + Vector3d vtExtr ; + if ( ! GetVectorParam( vsParams[3], vtExtr)) + return false ; + // creo la superficie + PtrOwner pSTM( CreateSurfTriMesh()) ; + if ( ! IsValid( pSTM)) + return false ; + // costruisco l'estrusione + if ( ! pSTM->CreateByExtrusion( PL, vtExtr)) + return false ; + // inserisco la superficie trimesh nel DB + return AddGeoObj( vsParams[0], vsParams[1], Release( pSTM)) ; + } else return false ; } @@ -1598,6 +1706,28 @@ GdbExecutor::ExecuteInvertCurve( const std::string& sCmd2, const STRVECTOR& vsPa return true ; } +//---------------------------------------------------------------------------- +bool +GdbExecutor::ExecuteInvertSurf( const std::string& sCmd2, const STRVECTOR& vsParams) +{ + // 1 parametro ( Nome/i) + if ( vsParams.size() != 1) + return false ; + // recupero lista nomi + INTVECTOR vnNames ; + if ( ! GetNamesParam( vsParams[0], vnNames)) + return false ; + // esecuzione inversione normale superficie + INTVECTOR::iterator Iter ; + for ( Iter = vnNames.begin() ; Iter != vnNames.end() ; ++Iter) { + ISurf* pSurf = GetSurf( m_pGDB->GetGeoObj( *Iter)) ; + if ( pSurf == nullptr || ! pSurf->Invert()) + return false ; + } + + return true ; +} + //---------------------------------------------------------------------------- bool GdbExecutor::ExecuteTrimCurve( const std::string& sCmd2, const STRVECTOR& vsParams) diff --git a/GdbExecutor.h b/GdbExecutor.h index 5c5b4a7..d83c33e 100644 --- a/GdbExecutor.h +++ b/GdbExecutor.h @@ -67,6 +67,7 @@ class GdbExecutor : public IGdbExecutor bool ExecuteScale( const std::string& sCmd2, const STRVECTOR& vsParams) ; bool ExecuteMirror( const std::string& sCmd2, const STRVECTOR& vsParams) ; bool ExecuteInvertCurve( const std::string& sCmd2, const STRVECTOR& vsParams) ; + bool ExecuteInvertSurf( const std::string& sCmd2, const STRVECTOR& vsParams) ; bool ExecuteTrimCurve( const std::string& sCmd2, const STRVECTOR& vsParams) ; bool ExecuteNew( const std::string& sCmd2, const STRVECTOR& vsParams) ; bool ExecuteLoad( const std::string& sCmd2, const STRVECTOR& vsParams) ; diff --git a/PolyLine.cpp b/PolyLine.cpp index bd28f29..3b811f7 100644 --- a/PolyLine.cpp +++ b/PolyLine.cpp @@ -14,6 +14,7 @@ //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "\EgtDev\Include\EGkPolyLine.h" +#include "\EgtDev\Include\EGkPlane3d.h" //---------------------------------------------------------------------------- @@ -28,6 +29,16 @@ PolyLine::~PolyLine( void) { } +//---------------------------------------------------------------------------- +bool +PolyLine::Clear( void) +{ + m_nCount = 0 ; + m_lUPoints.clear() ; + m_iter = m_lUPoints.end() ; + return true ; +} + //---------------------------------------------------------------------------- bool PolyLine::AddUPoint( double dPar, const Point3d& ptP) @@ -48,7 +59,7 @@ PolyLine::AddUPoint( double dPar, const Point3d& ptP) bool PolyLine::EraseFirstUPoint( void) { - if ( m_lUPoints.begin() == m_lUPoints.end()) + if ( m_lUPoints.empty()) return false ; m_lUPoints.pop_front() ; @@ -57,6 +68,19 @@ PolyLine::EraseFirstUPoint( void) return true ; } +//---------------------------------------------------------------------------- +bool +PolyLine::EraseLastUPoint( void) +{ + if ( m_lUPoints.empty()) + return false ; + + m_lUPoints.pop_back() ; + m_nCount -- ; + + return true ; +} + //---------------------------------------------------------------------------- bool PolyLine::AddOffsetToU( double dOffset) @@ -76,10 +100,21 @@ PolyLine::Splice( PolyLine& PL) { m_lUPoints.splice( m_lUPoints.end(), PL.m_lUPoints) ; m_nCount += PL.GetPointNbr() ; + PL.m_nCount = 0 ; return true ; } +//---------------------------------------------------------------------------- +bool +PolyLine::IsClosed( void) const +{ + if ( m_lUPoints.empty()) + return false ; + + return ( AreSamePointNear( m_lUPoints.front().second, m_lUPoints.back().second)) ; +} + //---------------------------------------------------------------------------- bool PolyLine::GetFirstUPoint( double* pdPar, Point3d* pptP) const @@ -116,7 +151,12 @@ PolyLine::GetNextUPoint( double* pdPar, Point3d* pptP) const bool PolyLine::GetLastUPoint( double* pdPar, Point3d* pptP) const { - if ( m_lUPoints.begin() == m_lUPoints.end()) + m_iter = m_lUPoints.end() ; + if ( m_iter == m_lUPoints.begin()) + return false ; + -- m_iter ; + + if ( m_iter == m_lUPoints.end()) return false ; if ( pdPar != nullptr) @@ -127,6 +167,22 @@ PolyLine::GetLastUPoint( double* pdPar, Point3d* pptP) const return true ; } +//---------------------------------------------------------------------------- +bool +PolyLine::GetPrevUPoint( double* pdPar, Point3d* pptP) const +{ + if ( m_iter == m_lUPoints.begin()) + return false ; + -- m_iter ; + + if ( pdPar != nullptr) + *pdPar = m_iter->first ; + if ( pptP != nullptr) + *pptP = m_iter->second ; + + return true ; +} + //---------------------------------------------------------------------------- bool PolyLine::GetFirstULine( double* pdIni, Point3d* pptIni, double* pdFin, Point3d* pptFin) const @@ -176,3 +232,60 @@ PolyLine::GetNextULine( double* pdIni, Point3d* pptIni, double* pdFin, Point3d* return true ; } +//---------------------------------------------------------------------------- +bool +PolyLine::NewellPlane( Plane3d& plPlane) const +{ + // Compute normal as being proportional to projected areas of polygon onto the yz, + // xz, and xy planes. Also compute centroid as representative point on the plane + Vector3d vtN ; + Point3d ptCen ; + int nNumSide = 0 ; + Point3d ptIni, ptFin ; + for ( bool bFound = GetFirstLine( ptIni, ptFin) ; bFound ; bFound = GetNextLine( ptIni, ptFin)) { + vtN.x += ( ptIni.y - ptFin.y) * ( ptIni.z + ptFin.z) ; // projection on yz + vtN.y += ( ptIni.z - ptFin.z) * ( ptIni.x + ptFin.x) ; // projection on xz + vtN.z += ( ptIni.x - ptFin.x) * ( ptIni.y + ptFin.y) ; // projection on xy + ptCen += ptFin ; + ++ nNumSide ; + } + // If open and existent, add segment from last to first points + if ( ! IsClosed() && nNumSide > 0) { + ptIni = ptFin ; + GetFirstPoint( ptFin) ; + vtN.x += ( ptIni.y - ptFin.y) * ( ptIni.z + ptFin.z) ; // projection on yz + vtN.y += ( ptIni.z - ptFin.z) * ( ptIni.x + ptFin.x) ; // projection on xz + vtN.z += ( ptIni.x - ptFin.x) * ( ptIni.y + ptFin.y) ; // projection on xy + ptCen += ptFin ; + ++ nNumSide ; + } + // At least 3 sides + if ( nNumSide < 3) + return false ; + // Normal must be normalizable + if ( ! vtN.Normalize()) + return false ; + // Normalize normal and fill in the plane equation fields + plPlane.vtN = vtN ; + plPlane.dDist = ( ( ptCen - ORIG) * plPlane.vtN) / nNumSide ; // “centroid / n” is the true centroid point + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PolyLine::IsPlanar( Plane3d& plPlane, double dToler) const +{ + // Compute a representative plane for the polygon + if ( ! NewellPlane( plPlane)) + return false ; + // 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.vtN) - plPlane.dDist ; + if ( fabs( dDist) > dToler) + return false ; + } + // All points passed distance test, so polygon is considered planar + return true ; +} diff --git a/StringUtils3d.cpp b/StringUtils3d.cpp index 17756fd..bf6dca5 100644 --- a/StringUtils3d.cpp +++ b/StringUtils3d.cpp @@ -17,89 +17,44 @@ using namespace std ; -//---------------------------------------------------------------------------- -bool -FromString( const string& sVal, Vector3d& vtVal) -{ - // divido la stringa in parametri - STRVECTOR vsParams ; - Tokenize( sVal, ",", vsParams) ; - // devono essere 3 parametri : x, y, z - if ( vsParams.size() != 3) - return false ; - // recupero il punto - return ( FromString( vsParams[0], vtVal.x) && - FromString( vsParams[1], vtVal.y) && - FromString( vsParams[2], vtVal.z)) ; -} - -//---------------------------------------------------------------------------- -bool -FromString( const string& sVal, Point3d& ptVal) -{ - // divido la stringa in parametri - STRVECTOR vsParams ; - Tokenize( sVal, ",", vsParams) ; - // devono essere 3 parametri : x, y, z - if ( vsParams.size() != 3) - return false ; - // recupero il punto - return ( FromString( vsParams[0], ptVal.x) && - FromString( vsParams[1], ptVal.y) && - FromString( vsParams[2], ptVal.z)) ; -} - //---------------------------------------------------------------------------- bool FromString( const string& sVal, Point3d& ptVal, double& dW) { - // divido la stringa in parametri - STRVECTOR vsParams ; - Tokenize( sVal, ",", vsParams) ; - // devono essere 4 parametri : x, y, z, w - if ( vsParams.size() != 4) + double vdVal[4] ; + if ( ! FromString( sVal, vdVal)) return false ; - // recupero il punto - return ( FromString( vsParams[0], ptVal.x) && - FromString( vsParams[1], ptVal.y) && - FromString( vsParams[2], ptVal.z) && - FromString( vsParams[3], dW)) ; + ptVal.x = vdVal[0] ; + ptVal.y = vdVal[1] ; + ptVal.z = vdVal[2] ; + dW = vdVal[3] ; + return true ; } //---------------------------------------------------------------------------- bool FromString( const string& sVal, Frame3d& frFrame) { - // divido la stringa in parametri - STRVECTOR vsParams ; - Tokenize( sVal, ",", vsParams) ; // devono essere 12 parametri : Ox, Oy, Oz, Xx, Xy, Xz, Yx, Yy, Yz, Zx, Zy, Zz - if ( vsParams.size() != 12) + double vdVal[12] ; + if ( ! FromString( sVal, vdVal)) return false ; - // recupero l'origine Point3d ptOrig ; - if ( ! FromString( vsParams[0], ptOrig.x) || - ! FromString( vsParams[1], ptOrig.y) || - ! FromString( vsParams[2], ptOrig.z)) - return false ; - // recupero il versore X + ptOrig.x = vdVal[0] ; + ptOrig.y = vdVal[1] ; + ptOrig.z = vdVal[2] ; Vector3d vtDirX ; - if ( ! FromString( vsParams[3], vtDirX.x) || - ! FromString( vsParams[4], vtDirX.y) || - ! FromString( vsParams[5], vtDirX.z)) - return false ; - // recupero il versore Y + vtDirX.x = vdVal[3] ; + vtDirX.y = vdVal[4] ; + vtDirX.z = vdVal[5] ; Vector3d vtDirY ; - if ( ! FromString( vsParams[6], vtDirY.x) || - ! FromString( vsParams[7], vtDirY.y) || - ! FromString( vsParams[8], vtDirY.z)) - return false ; - // recupero il versore Z + vtDirY.x = vdVal[6] ; + vtDirY.y = vdVal[7] ; + vtDirY.z = vdVal[8] ; Vector3d vtDirZ ; - if ( ! FromString( vsParams[9], vtDirZ.x) || - ! FromString( vsParams[10], vtDirZ.y) || - ! FromString( vsParams[11], vtDirZ.z)) - return false ; + vtDirZ.x = vdVal[9] ; + vtDirZ.y = vdVal[10] ; + vtDirZ.z = vdVal[11] ; // imposto il riferimento return frFrame.Set( ptOrig, vtDirX, vtDirY, vtDirZ) ; } @@ -108,20 +63,11 @@ FromString( const string& sVal, Frame3d& frFrame) bool FromString( const string& sVal, Color& cCol) { - // divido la stringa in parametri - STRVECTOR vsParams ; - Tokenize( sVal, ",", vsParams) ; // devono essere 4 parametri : Red, Green, Blue, Alpha - if ( vsParams.size() != 4) - return false ; - // recupero i parametri - int nRed, nGreen, nBlue, nAlpha ; - if ( ! FromString( vsParams[0], nRed) || - ! FromString( vsParams[1], nGreen) || - ! FromString( vsParams[2], nBlue) || - ! FromString( vsParams[3], nAlpha)) + int vnVal[4] ; + if ( ! FromString( sVal, vnVal)) return false ; // assegno il colore - cCol.Set( nRed, nGreen, nBlue, nAlpha) ; + cCol.Set( vnVal[0], vnVal[1], vnVal[2], vnVal[3]) ; return true ; } diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index 6233b59..e356b0b 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -13,15 +13,11 @@ //--------------------------- Include ---------------------------------------- #include "stdafx.h" -#include "DllMain.h" #include "SurfTriMesh.h" -#include "GeoConst.h" -#include "DistPointLine.h" #include "GeoObjFactory.h" -#include "PolynomialPoint3d.h" -#include "\EgtDev\Include\EGkCurveArc.h" -#include "\EgtDev\Include\ENkPolynomial.h" +#include "Triangulate.h" #include "\EgtDev\Include\EGkStringUtils3d.h" +#include "\EgtDev\Include\EGkPolyLine.h" #include using namespace std ; @@ -73,7 +69,7 @@ SurfTriMesh::AddVertex( const Point3d& ptVert) m_OGrMgr.Reset() ; // inserisco il vertice try { m_vVert.push_back( StmVert( ptVert)) ;} - catch(...) { return - 1 ;} + catch(...) { return VT_NULL ;} // ne determino l'indice return int( m_vVert.size() - 1) ; } @@ -95,9 +91,11 @@ SurfTriMesh::SetVertex( int nInd, const StmVert& vV) try { m_vVert.resize( nNewSize) ; } catch (...) { return false ; } // inizializzo a cancellati gli eventuali vertici intermedi - StmVert vEmpty( Point3d(), VT_DEL, 0) ; - for ( int i = nPrevSize ; i < nNewSize ; ++ i) - m_vVert[i] = vEmpty ; + if ( ( nNewSize - nPrevSize) > 1) { + StmVert vEmpty( Point3d(), VT_DEL, 0) ; + for ( int i = nPrevSize ; i < nNewSize ; ++ i) + m_vVert[i] = vEmpty ; + } } // inserisco il vertice m_vVert[nInd] = vV ; @@ -112,7 +110,8 @@ SurfTriMesh::AddTriangle( const int nIdVert[3]) m_nStatus = TO_VERIFY ; m_OGrMgr.Reset() ; // inserisco il triangolo - m_vTria.push_back( StmTria( nIdVert)) ; + try { m_vTria.push_back( StmTria( nIdVert)) ;} + catch(...) { return VT_NULL ;} // ne determino l'indice return int( m_vTria.size() - 1) ; } @@ -134,10 +133,12 @@ SurfTriMesh::SetTriangle( int nInd, const StmTria& tT) try { m_vTria.resize( nNewSize) ; } catch (...) { return false ; } // inizializzo a cancellati gli eventuali triangoli intermedi - StmTria tEmpty ; - tEmpty.nIdVert[0] = VT_DEL ; - for ( int i = nPrevSize ; i < nNewSize ; ++ i) - m_vTria[i] = tEmpty ; + if ( ( nNewSize - nPrevSize) > 1) { + StmTria tEmpty ; + tEmpty.nIdVert[0] = VT_DEL ; + for ( int i = nPrevSize ; i < nNewSize ; ++ i) + m_vTria[i] = tEmpty ; + } } // inserisco il vertice m_vTria[nInd] = tT ; @@ -148,7 +149,7 @@ SurfTriMesh::SetTriangle( int nInd, const StmTria& tT) int SurfTriMesh::GetFirstVertex( Point3d& ptP) const { - return GetNextVertex( -1, ptP) ; + return GetNextVertex( VT_NULL, ptP) ; } //---------------------------------------------------------------------------- @@ -161,7 +162,7 @@ SurfTriMesh::GetNextVertex( int nId, Point3d& ptP) const } while ( nId < GetVertexNum() && m_vVert[nId].nIdTria == VT_DEL) ; // se oltrepassata fine if ( nId >= GetVertexNum()) - return -1 ; + return VT_NULL ; // recupero i dati ptP = m_vVert[nId].ptP ; // ritorno indice triangolo corrente @@ -172,7 +173,7 @@ SurfTriMesh::GetNextVertex( int nId, Point3d& ptP) const int SurfTriMesh::GetFirstTriangle( Triangle3d& Tria) const { - return GetNextTriangle( -1, Tria) ; + return GetNextTriangle( VT_NULL, Tria) ; } //---------------------------------------------------------------------------- @@ -185,7 +186,7 @@ SurfTriMesh::GetNextTriangle( int nId, Triangle3d& Tria) const } while ( nId < GetTriangleNum() && m_vTria[nId].nIdVert[0] == VT_DEL) ; // se oltrepassata fine if ( nId >= GetTriangleNum()) - return -1 ; + return VT_NULL ; // recupero i dati Tria.Set( m_vVert[m_vTria[nId].nIdVert[0]].ptP, m_vVert[m_vTria[nId].nIdVert[1]].ptP, @@ -195,6 +196,66 @@ SurfTriMesh::GetNextTriangle( int nId, Triangle3d& Tria) const return nId ; } +//---------------------------------------------------------------------------- +bool +SurfTriMesh::GetTriangleSmoothNormals( int nId, TriNormals3d& TNrms) const +{ + // verifico esistenza del triangolo + if ( nId >= GetTriangleNum() || m_vTria[nId].nIdVert[0] == VT_DEL) + return false ; + + // recupero le normali di ciascun vertice + for ( int i = 0 ; i < 3 ; ++ i) { + if ( ! GetTriangleSmoothNormal( nId, i, TNrms.vtN[i])) + TNrms.vtN[i] = m_vTria[nId].vtN ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::GetTriangleSmoothNormal( int nT, int nV, Vector3d& vtN) const +{ + // recupero tutti i triangoli attorno al vertice + INTVECTOR vT ; + int nTria = GetAllTriaAroundVertex( m_vTria[nT].nIdVert[nV], vT) ; + if ( nTria < 1) + return false ; + + // cerco indice del triangolo corrente + int nPos = - 1 ; + for ( int i = 0 ; i < int( vT.size()) ; ++ i) { + if ( vT[i] == nT) { + nPos = i ; + break ; + } + } + if ( nPos == -1) + return false ; + + // medio le normali, finché non incontro degli spigoli + vtN = m_vTria[nT].vtN ; + const double COS_DEV_LIM = cos( 18 * DEGTORAD) ; + // parto dal triangolo e vado in direzione positiva + for ( int i = nPos + 1 ; i < int( vT.size()) ; ++ i) { + if ( m_vTria[vT[nPos]].vtN * m_vTria[vT[i]].vtN >= COS_DEV_LIM) + vtN += m_vTria[vT[i]].vtN ; + else + break ; + } + // parto dal triangolo e vado in direzione negativa + for ( int i = nPos - 1 ; i >= 0 ; -- i) { + if ( m_vTria[vT[nPos]].vtN * m_vTria[vT[i]].vtN >= COS_DEV_LIM) + vtN += m_vTria[vT[i]].vtN ; + else + break ; + } + vtN.Normalize() ; + + return true ; + } + //---------------------------------------------------------------------------- SurfTriMesh* SurfTriMesh::Clone( void) const @@ -359,7 +420,7 @@ SurfTriMesh::Load( Scanner& TheScanner) return false ; // la divido in parametri Tokenize( sLine, ";", vsParams) ; - // 6 parametri : Indice, Punto, IdTria, Flag + // 6 parametri : Indice, IdVertici, IdAdiacenze, Normale, TFlag, EFlag if ( vsParams.size() != 6) return false ; // la interpreto e imposto il vertice @@ -414,7 +475,7 @@ SurfTriMesh::Validate( void) //---------------------------------------------------------------------------- bool -SurfTriMesh::FindVertexInTria( int nV, int nT, int& nK) +SurfTriMesh::FindVertexInTria( int nV, int nT, int& nK) const { nK = - 1 ; for ( int k = 0 ; k < 3 ; k ++) { @@ -428,7 +489,7 @@ SurfTriMesh::FindVertexInTria( int nV, int nT, int& nK) //---------------------------------------------------------------------------- int -SurfTriMesh::GetAllTriaAroundVertex( int nV, INTVECTOR& vT) +SurfTriMesh::GetAllTriaAroundVertex( int nV, INTVECTOR& vT) const { const int MAX_VT_SIZE = 512 ; @@ -642,6 +703,107 @@ SurfTriMesh::AdjustTopology( void) return true ; } +//---------------------------------------------------------------------------- +bool +SurfTriMesh::CreateByTriangulation( const PolyLine& PL) +{ + // eseguo la triangolazione + PNTVECTOR vPnt ; + INTVECTOR vTria ; + Triangulate Tri ; + if ( ! Tri.Make( PL, 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]) == VT_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) == VT_NULL) + return false ; + } + + // sistemo la topologia + return AdjustTopology() ; +} + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::CreateByExtrusion( const PolyLine& PL, const Vector3d& vtExtr) +{ + // verifico che il vettore di estrusione sia non nullo + if ( vtExtr.IsSmall()) + return false ; + + // verifico se la polilinea è chiusa + bool bClosed = PL.IsClosed() ; + + // costruisco la mesh + int nPointNbr = PL.GetPointNbr() ; + if ( ! Init( 2 * nPointNbr, 2 * nPointNbr)) + 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) == VT_NULL || AddVertex( ptP + vtExtr) == VT_NULL) + return false ; + nV += 2 ; + // ciclo sui punti della polilinea (per inserire vertice e suo estruso + 2 triangoli per ogni punto) + 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) == VT_NULL || AddVertex( ptP + vtExtr) == VT_NULL) + return false ; + nV += 2 ; + // aggiungo triangolo in basso a sinistra + nIdV[0] = nV - 3 ; nIdV[1] = nV - 1 ; nIdV[2] = nV - 2 ; + if ( AddTriangle( nIdV) == VT_NULL) + return false ; + // aggiungo triangolo in alto a destra + nIdV[0] = nV - 2 ; nIdV[1] = nV - 1 ; nIdV[2] = nV ; + if ( AddTriangle( nIdV) == VT_NULL) + return false ; + } + // altrimenti ultimo punto di polilinea chiusa + 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 ; + if ( AddTriangle( nIdV) == VT_NULL) + return false ; + // aggiungo triangolo in alto a destra + nIdV[0] = nV ; nIdV[1] = 0 ; nIdV[2] = 1 ; + if ( AddTriangle( nIdV) == VT_NULL) + return false ; + } + } + + // sistemo la topologia + return AdjustTopology() ; +} + //---------------------------------------------------------------------------- bool SurfTriMesh::GetLocalBBox( BBox3d& b3Loc) const @@ -852,7 +1014,7 @@ SurfTriMesh::Mirror( const Point3d& ptOn, const Vector3d& vtNorm) bool SurfTriMesh::ToGlob( const Frame3d& frRef) { - // la curva deve essere validata + // la superficie deve essere validata if ( m_nStatus != OK) return false ; @@ -861,8 +1023,10 @@ SurfTriMesh::ToGlob( const Frame3d& frRef) return false ; // trasformo i vertici - for ( int i = 0 ; i < GetVertexNum() ; ++ i) - m_vVert[i].ptP.ToGlob( frRef) ; + for ( int i = 0 ; i < GetVertexNum() ; ++ i) { + if ( m_vVert[i].nIdTria != VT_DEL) + m_vVert[i].ptP.ToGlob( frRef) ; + } // imposto ricalcolo della grafica m_OGrMgr.Reset() ; @@ -874,7 +1038,7 @@ SurfTriMesh::ToGlob( const Frame3d& frRef) bool SurfTriMesh::ToLoc( const Frame3d& frRef) { - // la curva deve essere validata + // la superficie deve essere validata if ( m_nStatus != OK) return false ; @@ -883,8 +1047,28 @@ SurfTriMesh::ToLoc( const Frame3d& frRef) return false ; // trasformo i vertici - for ( int i = 0 ; i < GetVertexNum() ; ++ i) - m_vVert[i].ptP.ToLoc( frRef) ; + for ( int i = 0 ; i < GetVertexNum() ; ++ i) { + if ( m_vVert[i].nIdTria != VT_DEL) + m_vVert[i].ptP.ToLoc( frRef) ; + } + + // imposto ricalcolo della grafica + m_OGrMgr.Reset() ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::Invert( void) +{ + // la superficie deve essere validata + if ( m_nStatus != OK) + return false ; + + // inverto i triangoli + for ( int i = 0 ; i < GetTriangleNum() ; ++ i) + InvertTriangle( i) ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; diff --git a/SurfTriMesh.h b/SurfTriMesh.h index 009cb20..ff7947c 100644 --- a/SurfTriMesh.h +++ b/SurfTriMesh.h @@ -94,6 +94,7 @@ class SurfTriMesh : public ISurfTriMesh { return true ; } virtual bool IsClosed( void) const { return m_bClosed ; } + virtual bool Invert( void) ; public : // ISurfTriMesh virtual bool Copy( const IGeoObj* pGObjSrc) ; @@ -101,6 +102,8 @@ class SurfTriMesh : public ISurfTriMesh 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 CreateByExtrusion( const PolyLine& PL, const Vector3d& vtExtr) ; virtual int GetVertexNum( void) const { return int( m_vVert.size()) ; } virtual int GetTriangleNum( void) const @@ -109,6 +112,7 @@ class SurfTriMesh : public ISurfTriMesh virtual int GetNextVertex( int nId, Point3d& ptP) const ; virtual int GetFirstTriangle( Triangle3d& Tria) const ; virtual int GetNextTriangle( int nId, Triangle3d& Tria) const ; + virtual bool GetTriangleSmoothNormals( int nId, TriNormals3d& TNrms) const ; public : SurfTriMesh( void) ; @@ -127,12 +131,13 @@ class SurfTriMesh : public ISurfTriMesh bool SetTriangle( int nInd, const StmTria& tT) ; bool CalcTriangleNormal( int nT) ; bool InvertTriangle( int nT) ; - int Next( int i) + int Next( int i) const { return (( i + 1) % 3) ; } - int Prev( int i) + int Prev( int i) const { return (( i + 2) % 3) ; } - bool FindVertexInTria( int nV, int nT, int& nK) ; - int GetAllTriaAroundVertex( int nV, INTVECTOR& vT) ; + bool FindVertexInTria( int nV, int nT, int& nK) const ; + int GetAllTriaAroundVertex( int nV, INTVECTOR& vT) const ; + bool GetTriangleSmoothNormal( int nT, int nV, Vector3d& vtN) const ; private : enum Status { ERR = 0, OK = 1, TO_VERIFY = 2} ; diff --git a/Triangulate.cpp b/Triangulate.cpp new file mode 100644 index 0000000..a18f412 --- /dev/null +++ b/Triangulate.cpp @@ -0,0 +1,209 @@ +//---------------------------------------------------------------------------- +// EgalTech 2014-2014 +//---------------------------------------------------------------------------- +// File : Triangulate.cpp Data : 08.04.14 Versione : 1.5d2 +// Contenuto : Implementazione della classe Triangulate. +// +// +// +// Modifiche : 08.04.14 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "Triangulate.h" +#include "\EgtDev\Include\EGkPolyLine.h" +#include "\EgtDev\Include\EGkPlane3d.h" + +//---------------------------------------------------------------------------- +// In : PolyLine +// Out : PNTVECTOR (Point3d Vector) : points of the polyline +// INTVECTOR (int Vector) : 3*T indices of above points for T triangles +//---------------------------------------------------------------------------- +bool +Triangulate::Make( const PolyLine& PL, PNTVECTOR& vPt, INTVECTOR& vTr) +{ + // verifico che la polilinea sia chiusa -> poligono + if ( ! PL.IsClosed()) + return false ; + // calcolo il piano medio del poligono + Plane3d plPlane ; + if ( ! PL.IsPlanar( plPlane, 50 * EPS_SMALL)) + return false ; + int nPlane ; + bool bCCW ; + if ( fabs( plPlane.vtN.z) >= fabs( plPlane.vtN.x) && + fabs( plPlane.vtN.z) >= fabs( plPlane.vtN.y)) { + nPlane = PL_XY ; + bCCW = ( plPlane.vtN.z > 0) ; + } + else if ( fabs( plPlane.vtN.x) >= fabs( plPlane.vtN.y)) { + nPlane = PL_YZ ; + bCCW = ( plPlane.vtN.x > 0) ; + } + else { + nPlane = PL_ZX ; + bCCW = ( plPlane.vtN.y > 0) ; + } + // riempio il vettore con i vertici del poligono da triangolare + vPt.clear() ; + vPt.reserve( PL.GetPointNbr() - 1) ; + // se orientato correttamente (componente di N > 0) + if ( bCCW) { + // salto il primo punto (coincide con l'ultimo) + Point3d ptP ; + if ( ! PL.GetFirstPoint( ptP)) + return false ; + // inserisco i punti + while ( PL.GetNextPoint( ptP)) + vPt.push_back( ptP) ; + } + // altrimenti lo prendo al contrario + else { + // salto l'ultimo punto (coincide con il primo) + Point3d ptP ; + if ( ! PL.GetLastPoint( ptP)) + return false ; + // inserisco i punti + while ( PL.GetPrevPoint( ptP)) + vPt.push_back( ptP) ; + } + + // eseguo la triangolazione + return MakeByEC( vPt, nPlane, vTr) ; +} + +//---------------------------------------------------------------------------- +// Triangulate the CCW n-gon specified by the vertices vPt (Pt[n] != Pt[0]) +// Ear Clipping algorithm +//---------------------------------------------------------------------------- +bool +Triangulate::MakeByEC( const PNTVECTOR& vPt, int nPlane, INTVECTOR& vTr) +{ + // At least 3 points + int n = int( vPt.size()) ; + if ( n < 3) + return false ; + + // Save the plane + if ( nPlane != PL_XY && nPlane != PL_YZ && nPlane != PL_ZX) + return false ; + m_nPlane = nPlane ; + + // Clear and preallocate triangle vector ( #triangles = n - 2) + vTr.clear() ; + vTr.reserve( 3 * ( n - 2)) ; + + // Set up previous and next links to effectively form a double-linked vertex list + INTVECTOR prev( n) ; + INTVECTOR next( n) ; + for ( int i = 0 ; i < n ; ++ i) { + prev[i] = i - 1 ; + next[i] = i + 1 ; + } + prev[0] = n - 1 ; + next[n - 1] = 0 ; + + // 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 + bool bIsEar = true ; + // An ear must be convex (here counterclockwise) + if ( TriangleIsCCW( vPt[prev[i]], vPt[i], vPt[next[i]])) { + // Loop over all vertices not part of the tentative ear + int k = next[next[i]] ; + do { + // If vertex k is inside the ear triangle, then this is not an ear + if ( TestPointInTriangle( vPt[k], vPt[prev[i]], vPt[i], vPt[next[i]])) { + bIsEar = false ; + break; + } + k = next[k] ; + } while (k != prev[i]) ; + } + else { + // The ‘ear’ triangle is clockwise so v[i] is not an ear + bIsEar = false ; + } + + // 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( prev[i]) ; + vTr.push_back( i) ; + vTr.push_back( next[i]) ; + // ‘Delete’ vertex v[i] by redirecting next and previous links + // of neighboring verts past it. Decrement vertex count + next[prev[i]] = next[i] ; + prev[next[i]] = prev[i] ; + n--; + // Visit the previous vertex next + i = prev[i] ; + // Reset Count + nCount = n ; + } + else { + // Current vertex is not an ear; visit the next vertex + i = next[i] ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +Triangulate::TriangleIsCCW( const Point3d& ptA, const Point3d& ptB, const Point3d& ptC) +{ + double dV11 ; + double dV12 ; + double dV21 ; + double dV22 ; + + 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) > 0) ; +} + +//---------------------------------------------------------------------------- +// Test if point p is contained in triangle (a, b, c) +bool +Triangulate::TestPointInTriangle( const Point3d& ptP, const Point3d& ptA, const Point3d& ptB, const Point3d& ptC) +{ + if ( ! TriangleIsCCW( ptA, ptB, ptP)) + return false ; + if ( ! TriangleIsCCW( ptB, ptC, ptP)) + return false ; + if ( ! TriangleIsCCW( ptC, ptA, ptP)) + return false ; + return true ; +} + diff --git a/Triangulate.h b/Triangulate.h new file mode 100644 index 0000000..24ac50c --- /dev/null +++ b/Triangulate.h @@ -0,0 +1,35 @@ +//---------------------------------------------------------------------------- +// EgalTech 2014-2014 +//---------------------------------------------------------------------------- +// File : SurfTriMesh.h Data : 26.03.14 Versione : 1.5c9 +// Contenuto : Dichiarazione della classe Superfici TriMesh. +// +// +// +// Modifiche : 26.03.14 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#pragma once +#include "/EgtDev/Include/EGkGeoCollection.h" + +class PolyLine ; + +//---------------------------------------------------------------------------- +enum { PL_XY = 1, PL_YZ = 2, PL_ZX = 3} ; + +//---------------------------------------------------------------------------- +class Triangulate +{ + public : + bool Make( const PolyLine& PL, PNTVECTOR& vPt, INTVECTOR& vTr) ; + bool MakeByEC( const PNTVECTOR& vPt, int nPlane, INTVECTOR& vTr) ; + + private : + bool TriangleIsCCW( const Point3d& ptA, const Point3d& ptB, const Point3d& ptC) ; + bool TestPointInTriangle( const Point3d& ptP, const Point3d& ptA, const Point3d& ptB, const Point3d& ptC) ; + + private : + int m_nPlane ; +} ; \ No newline at end of file