//---------------------------------------------------------------------------- // EgalTech 2023-2023 //---------------------------------------------------------------------------- // File : PolygonElevation.cpp Data : 17.12.23 Versione : 2.5l3 // Contenuto : Implementazione di funzioni per calcolo elevazione di // un poligono (faccia piana) in solidi di diverso tipo. // // // Modifiche : 17.12.23 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "CurveLine.h" #include "CurveComposite.h" #include "/EgtDev/Include/EGkIntersLineBox.h" #include "/EgtDev/Include/EGkIntersLineSurfTm.h" #include "/EgtDev/Include/EGkIntersCurves.h" #include "/EgtDev/Include/EGkPolygonElevation.h" using namespace std ; //------------------------------------------------------------------------------- bool PolygonElevationInBBox( const Polygon3d& pgFacet, const BBox3d& b3Box, bool bAcceptOutFacet, double& dElev) { // verifico validità del poligono e del box if ( ! pgFacet.IsValid() || b3Box.IsEmpty()) return false ; // se richiesto, verifico che la faccia sia contenuta nel box if ( ! bAcceptOutFacet) { BBox3d b3Fac ; if ( ! pgFacet.GetLocalBBox( b3Fac)) return false ; BBox3d b3ExpBox = b3Box ; b3ExpBox.Expand( 100 * EPS_SMALL) ; if ( ! b3ExpBox.Encloses( b3Fac)) { dElev = -1 ; return true ; } } // recupero centro, normale e contorno delle faccia poligonale Point3d ptCen = pgFacet.GetCentroid() ; Vector3d vtN = pgFacet.GetVersN() ; PolyLine PL = pgFacet.GetPolyLine() ; // calcolo elevazione massima del contorno della faccia const double RAY_LEN = 100000 ; dElev = 0 ; Point3d ptP ; bool bFound = PL.GetFirstPoint( ptP) ; while ( bFound) { INTDBLVECTOR vInters ; IntersLineBox( ptP, vtN, RAY_LEN, b3Box, vInters, true) ; for ( int i = 0 ; i < int( vInters.size()) ; ++ i) { if ( i == 0 && ( vInters[i].first == ILBT_IN || vInters[i].first == ILBT_TG_INI)) { if ( ! bAcceptOutFacet && vInters[i].second > 100 * EPS_SMALL) { dElev = -1 ; return true ; } } else if ( vInters[i].first == ILBT_OUT || vInters[i].first == ILBT_TG_FIN) dElev = max( dElev, vInters[i].second) ; } bFound = PL.GetNextPoint( ptP, true) ; } // calcolo elevazione massima degli eventuali spigoli (e vertici) del box dalla parte positiva della faccia e che cadono in essa BIPNTVECTOR vEdges( 12) ; vEdges[0].first = b3Box.GetMin() ; vEdges[0].second = vEdges[0].first + b3Box.GetDimX() * X_AX ; vEdges[1].first = vEdges[0].second ; vEdges[1].second = vEdges[1].first + b3Box.GetDimY() * Y_AX ; vEdges[2].first = vEdges[1].second ; vEdges[2].second = vEdges[0].first + b3Box.GetDimY() * Y_AX ; vEdges[3].first = vEdges[2].second ; vEdges[3].second = vEdges[0].first ; vEdges[4].first = vEdges[0].first + b3Box.GetDimZ() * Z_AX ; vEdges[4].second = vEdges[0].second + b3Box.GetDimZ() * Z_AX ; vEdges[5].first = vEdges[1].first + b3Box.GetDimZ() * Z_AX ; vEdges[5].second = vEdges[1].second + b3Box.GetDimZ() * Z_AX ; vEdges[6].first = vEdges[2].first + b3Box.GetDimZ() * Z_AX ; vEdges[6].second = vEdges[2].second + b3Box.GetDimZ() * Z_AX ; vEdges[7].first = vEdges[3].first + b3Box.GetDimZ() * Z_AX ; vEdges[7].second = vEdges[3].second + b3Box.GetDimZ() * Z_AX ; vEdges[8].first = vEdges[0].first ; vEdges[8].second = vEdges[4].first ; vEdges[9].first = vEdges[1].first ; vEdges[9].second = vEdges[5].first ; vEdges[10].first = vEdges[2].first ; vEdges[10].second = vEdges[6].first ; vEdges[11].first = vEdges[3].first ; vEdges[11].second = vEdges[7].first ; // porto tutto nel riferimento intrinseco della faccia (già calcolato in quello del box) Frame3d frOcs ; frOcs.Set( ptCen, vtN) ; PL.ToLoc( frOcs) ; for ( int i = 0 ; i < int( vEdges.size()) ; ++ i) { vEdges[i].first.ToLoc( frOcs) ; vEdges[i].second.ToLoc( frOcs) ; } // calcolo la curva di loop CurveComposite ccLoop ; if ( ! ccLoop.FromPolyLine( PL)) return false ; // eseguo i calcoli di elevazione for ( int i = 0 ; i < int( vEdges.size()) ; ++ i) { // se sta sul piano o sotto, lo salto if ( vEdges[i].first.z < EPS_SMALL && vEdges[i].second.z < EPS_SMALL) continue ; // calcolo il segmento di linea CurveLine clLine ; if ( ! clLine.Set( vEdges[i].first, vEdges[i].second)) return false ; // l'elevazione va aggiornata con la massima Z delle eventuali intersezioni dell'edge con il loop IntersCurveCurve intLL( clLine, ccLoop) ; IntCrvCrvInfo aInfo ; for ( int j = 0 ; intLL.GetIntCrvCrvInfo( j, aInfo) ; ++ j) { dElev = max( dElev, aInfo.IciA[0].ptI.z) ; if ( aInfo.bOverlap) dElev = max( dElev, aInfo.IciA[1].ptI.z) ; // se prima intersezione va da interno ad esterno allora devo considerare il punto iniziale del segmento (vertice) if ( j == 0 && aInfo.IciA[0].nPrevTy == ICCT_IN) dElev = max( dElev, vEdges[i].first.z) ; // c'è anche il caso di ultima intersezione da esterno a interno, ma vertice già considerato nel caso precedente } } return true ; } //------------------------------------------------------------------------------- bool PolygonElevationInClosedSurfTm( const Polygon3d& pgFacet, const ISurfTriMesh& CldStm, bool bAcceptOutFacet, double& dElev) { // verifico validità del poligono e della superficie if ( ! pgFacet.IsValid() || ! CldStm.IsValid() || ! CldStm.IsClosed()) return false ; // se superficie vuota if ( CldStm.IsEmpty()) { dElev = ( bAcceptOutFacet ? 0 : -1) ; return true ; } // se richiesto, verifico sia contenuta nel box della superficie chiusa if ( ! bAcceptOutFacet) { BBox3d b3Fac ; if ( ! pgFacet.GetLocalBBox( b3Fac)) return false ; BBox3d b3ExpCldStm ; CldStm.GetLocalBBox( b3ExpCldStm) ; b3ExpCldStm.Expand( 100 * EPS_SMALL) ; if ( ! b3ExpCldStm.Encloses( b3Fac)) { dElev = -1 ; return true ; } } // recupero centro, normale e contorno delle faccia poligonale Point3d ptCen = pgFacet.GetCentroid() ; Vector3d vtN = pgFacet.GetVersN() ; PolyLine PL = pgFacet.GetPolyLine() ; // calcolo elevazione massima del contorno della faccia e nel suo centro const double RAY_LEN = 100000 ; dElev = 0 ; PNTVECTOR vptP ; vptP.reserve( PL.GetPointNbr()) ; Point3d ptP ; bool bFound = PL.GetFirstPoint( ptP) ; while ( bFound) { vptP.push_back( ptP) ; bFound = PL.GetNextPoint( ptP, true) ; } vptP.push_back( ptCen) ; for ( const Point3d& ptP : vptP) { ILSIVECTOR vInters ; IntersLineSurfTm( ptP, vtN, RAY_LEN, CldStm, vInters, true) ; for ( int i = 0 ; i < int( vInters.size()) ; ++ i) { const auto& Inters = vInters[i] ; if ( i == 0 && Inters.nILTT != ILTT_NO && Inters.dCosDN < -EPS_ZERO) { if ( ! bAcceptOutFacet && Inters.dU > 100 * EPS_SMALL) { dElev = -1 ; return true ; } } else if ( ( Inters.nILTT == ILTT_VERT || Inters.nILTT == ILTT_EDGE || Inters.nILTT == ILTT_IN) && Inters.dCosDN > EPS_ZERO) dElev = max( dElev, Inters.dU) ; else if ( Inters.nILTT == ILTT_SEGM || Inters.nILTT == ILTT_SEGM_ON_EDGE) dElev = max( dElev, Inters.dU2) ; } } // calcolo elevazione massima degli eventuali spigoli (e vertici) della superficie chiusa dalla parte positiva della faccia e che cadono in essa int nEdgeCnt = CldStm.GetEdgeCount() ; if ( nEdgeCnt < 0) return false ; BIPNTVECTOR vEdges ; vEdges.reserve( nEdgeCnt) ; for ( int i = 0 ; i < nEdgeCnt ; ++ i) { Point3d ptP1, ptP2 ; double dAng ; CldStm.GetEdge( i, ptP1, ptP2, dAng) ; vEdges.emplace_back( ptP1, ptP2) ; } // porto tutto nel riferimento intrinseco della faccia (già calcolato in quello della superficie chiusa) Frame3d frOcs ; frOcs.Set( ptCen, vtN) ; PL.ToLoc( frOcs) ; for ( int i = 0 ; i < int( vEdges.size()) ; ++ i) { vEdges[i].first.ToLoc( frOcs) ; vEdges[i].second.ToLoc( frOcs) ; } // calcolo la curva di loop CurveComposite ccLoop ; if ( ! ccLoop.FromPolyLine( PL)) return false ; // eseguo i calcoli di elevazione for ( int i = 0 ; i < int( vEdges.size()) ; ++ i) { // se sta sul piano o sotto, lo salto if ( vEdges[i].first.z < EPS_SMALL && vEdges[i].second.z < EPS_SMALL) continue ; // calcolo il segmento di linea CurveLine clLine ; if ( ! clLine.Set( vEdges[i].first, vEdges[i].second)) return false ; // l'elevazione va aggiornata con la massima Z delle eventuali intersezioni dell'edge con il loop IntersCurveCurve intLL( clLine, ccLoop) ; if ( intLL.GetIntersCount() == 0) { Point3d ptM = Media( vEdges[i].first, vEdges[i].second) ; ptM.z = 0 ; if ( IsPointInsidePolyLine( ptM, PL, -EPS_SMALL)) dElev = max( dElev, max( vEdges[i].first.z, vEdges[i].second.z)) ; } else { IntCrvCrvInfo aInfo ; for ( int j = 0 ; intLL.GetIntCrvCrvInfo( j, aInfo) ; ++ j) { dElev = max( dElev, aInfo.IciA[0].ptI.z) ; if ( aInfo.bOverlap) dElev = max( dElev, aInfo.IciA[1].ptI.z) ; // se prima intersezione va da interno ad esterno allora devo considerare il punto iniziale del segmento (vertice) if ( j == 0 && aInfo.IciA[0].nPrevTy == ICCT_IN) dElev = max( dElev, vEdges[i].first.z) ; // se ultima intersezione va da esterno a interno allora devo considerare il punto finale del segmento (vertice) else if ( j == intLL.GetIntersCount() - 1 && aInfo.IciA[ aInfo.bOverlap ? 1 : 0].nNextTy == ICCT_IN) dElev = max( dElev, vEdges[i].second.z) ; } } } return true ; }