//---------------------------------------------------------------------------- // EgalTech 2013-2021 //---------------------------------------------------------------------------- // File : SceneGeom.cpp Data : 11.03.21 Versione : 2.3c1 // Contenuto : Implementazione della gestione geometria della classe scena. // // // // Modifiche : 10.02.14 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "Scene.h" #include "ObjOldGraphics.h" #include "ObjNewGraphics.h" #include "ObjMultiGraphics.h" #include "EGrUtils.h" #include "DllMain.h" #include "/EgtDev/Include/EGkFrame3d.h" #include "/EgtDev/Include/EGkGdbIterator.h" #include "/EgtDev/Include/EGkGeoVector3d.h" #include "/EgtDev/Include/EGkGeoPoint3d.h" #include "/EgtDev/Include/EGkCurve.h" #include "/EgtDev/Include/EGkCurveComposite.h" #include "/EgtDev/Include/EGkSurfTriMesh.h" #include "/EgtDev/Include/EGkSurfFlatRegion.h" #include "/EgtDev/Include/EGkSurfBezier.h" #include "/EgtDev/Include/EGkVolZmap.h" #include "/EgtDev/Include/EGkExtText.h" #include "/EgtDev/Include/EGkExtDimension.h" #include "/EgtDev/Include/EGkGdbFunct.h" #include "/EgtDev/Include/EGnStringUtils.h" #include "/EgtDev/Include/EgtNumUtils.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include "/EgtDev/Include/EgtILogger.h" using namespace std ; //------------------------------ Local functions ----------------------------- static ObjEGrGraphics* CreateObjEGrGraphics( int nCount, bool bNewWay) ; static bool CalcCurveTailMark( const Vector3d& vtRef, const PolyLine& plCrv, PolyLine& plMark) ; static bool CalcCurveTipArrow( const Vector3d& vtRef, const PolyLine& plCrv, PolyLine& plArr) ; static bool CalcCurveConnectingLines( const PolyLine& plCrv, const Vector3d& vtTh, bool bDense, PNTVECTOR& vPnt) ; static bool CalcCurveJoints( const ICurve* pCurve, PNTVECTOR& vPnt) ; //---------------------------------------------------------------------------- bool Scene::UpdateExtension( void) { BBox3d b3Ext ; if ( m_pGeomDB == nullptr || ! m_pGeomDB->GetLocalBBox( GDB_ID_ROOT, b3Ext, BBF_ONLY_VISIBLE)) return false ; return SetExtension( b3Ext) ; } //---------------------------------------------------------------------------- bool Scene::SetMark( Color colMark) { m_colMark = colMark ; return true ; } //---------------------------------------------------------------------------- bool Scene::SetSelSurf( Color colSelSurf) { m_colSelSurf = colSelSurf ; return true ; } //---------------------------------------------------------------------------- bool Scene::SetLineWidth( int nW) { nW = Clamp( nW, 1, 3) ; switch ( nW) { case 1 : m_dLineWidth = 1 ; m_dSelLineWidth = 2 ; m_dMarkLineWidth = 5 ; m_dPointSize = 3 ; m_dSelPointSize = 5 ; m_dMarkPointSize = 7 ; break ; case 2 : m_dLineWidth = 2 ; m_dSelLineWidth = 4 ; m_dMarkLineWidth = 7 ; m_dPointSize = 4 ; m_dSelPointSize = 7 ; m_dMarkPointSize = 9 ; break ; case 3 : m_dLineWidth = 3 ; m_dSelLineWidth = 6 ; m_dMarkLineWidth = 9 ; m_dPointSize = 5 ; m_dSelPointSize = 9 ; m_dMarkPointSize = 11 ; break ; } return true ; } //---------------------------------------------------------------------------- bool Scene::DrawGroup( int nId, int nPass, const MdStMkCol& cParent) { // creo un iteratore PtrOwner pIter( CreateGdbIterator( m_pGeomDB)) ; if ( IsNull( pIter)) return false ; // recupero il gruppo if ( ! pIter->GoTo( nId)) return false ; // eseguo il disegno return DrawGroup( *pIter, nPass, cParent) ; } //---------------------------------------------------------------------------- bool Scene::DrawGroup( const IGdbIterator& iIter, int nPass, const MdStMkCol& cParent) { // creo un iteratore PtrOwner pIter( CreateGdbIterator( m_pGeomDB)) ; if ( IsNull( pIter)) return false ; // recupero il riferimento del gruppo Frame3d frFrame ; if ( ! iIter.GetGroupFrame( frFrame)) return false ; // se non è identità, lo aggiungo sullo stack delle matrici MODELVIEW di OpenGL bool bMatrix = ( frFrame.GetType() != Frame3d::TOP || ! frFrame.Orig().IsSmall()) ; if ( bMatrix) { glPushMatrix() ; double Matrix[OGLMAT_DIM] ; if ( FrameToOpenGlMatrix( frFrame, Matrix)) glMultMatrixd( Matrix) ; } // scandisco il gruppo bool bOk = true ; for ( bool bNext = pIter->GoToFirstInGroup( iIter) ; bNext ; bNext = pIter->GoToNext()) { // leggo il tipo di oggetto int nGdbType = pIter->GetGdbType() ; // recupero e aggiorno il modo dell'oggetto int nMode = GDB_MD_STD ; pIter->GetMode( nMode) ; nMode = ::CalcMode( nMode, cParent.nMode) ; // recupero e aggiorno lo stato dell'oggetto int nStat = GDB_ST_ON ; pIter->GetStatus( nStat) ; nStat = ::CalcStatus( nStat, cParent.nStat) ; nStat = ::AdjustStatusWithMode( nStat, nMode) ; // recupero e aggiorno la marcatura dell'oggetto int nMark = GDB_MK_OFF ; pIter->GetMark( nMark) ; nMark = ::CalcMark( nMark, cParent.nMark) ; // recupero e aggiorno il colore dell'oggetto Color colObj = cParent.colObj ; pIter->GetMaterial( colObj) ; // se in modalità selezione, verifico sia selezionabile bool bSel = true ; if ( m_bSelect && UnselectableFind( pIter->GetId())) bSel = false ; // se oggetto geometrico if ( nGdbType == GDB_TY_GEO) { // se non nascosto e selezionabile, lo disegno if ( nStat != GDB_ST_OFF && bSel) { if ( ! DrawGeoObj( *pIter, nPass, MdStMkCol( nMode, nStat, nMark, colObj))) bOk = false ; } } // se gruppo else if ( nGdbType == GDB_TY_GROUP) { // se non nascosto e selezionabile, lo disegno if ( nStat != GDB_ST_OFF && bSel) { if ( ! DrawGroup( *pIter, nPass, MdStMkCol( nMode, nStat, nMark, colObj))) bOk = false ; } } } // se necessario, ripristino lo stack delle matrici if ( bMatrix) glPopMatrix() ; return bOk ; } //---------------------------------------------------------------------------- static const ISurfTriMesh* GetSurfTriMeshAux( const IGeoObj* pGeoObj) { int nGeoType = pGeoObj->GetType() ; switch ( nGeoType) { case SRF_TRIMESH : return GetSurfTriMesh( pGeoObj) ; case SRF_FLATRGN : return GetSurfFlatRegion( pGeoObj)->GetAuxSurf() ; case SRF_BEZIER : return GetSurfBezier( pGeoObj)->GetAuxSurf() ; default : return nullptr ; } } //---------------------------------------------------------------------------- bool Scene::DrawGeoObj( const IGdbIterator& iIter, int nPass, const MdStMkCol& siObj) { // recupero l'oggetto geometrico e il suo tipo IGeoObj* pGeoObj = (const_cast(&iIter))->GetGeoObj() ; if ( pGeoObj == nullptr) return false ; int nGeoType = pGeoObj->GetType() ; // recupero eventuale parte custom const IUserObj* pUserObj = iIter.GetUserObj() ; // se non esiste grafica associata, la creo if ( pGeoObj->GetObjGraphics() == nullptr) { // oggetto grafico molteplice solo per Zmap o superfici che lo richiedono int nCount = 0 ; if ( nGeoType == VOL_ZMAP) { const IVolZmap* pZmap = GetVolZmap( pGeoObj) ; if ( pZmap != nullptr) { if ( ( m_nShowZmap & ZSM_SURF) != 0) nCount += 2 * pZmap->GetBlockCount() ; if ( ( m_nShowZmap & ZSM_LINES) != 0 || ( m_nShowZmap & ZSM_NORMALS) != 0) nCount += 1 ; } } else if (( nGeoType & GEO_SURF) != 0) { const ISurfTriMesh* pSTM = GetSurfTriMeshAux( pGeoObj) ; if ( pSTM != nullptr && pSTM->GetMaxTFlag() > 0) nCount = 2 ; } // nuova modalità grafica solo per superfici e testi con molti triangoli o solidi Zmap const int N_MIN_TRIA_NEWWAY = 100 ; bool bNewWay = false ; if ( m_bNewWay) { if ( ( nGeoType & GEO_SURF) != 0) { const ISurfTriMesh* pSTM = GetSurfTriMeshAux( pGeoObj) ; if ( pSTM != nullptr && pSTM->GetTriangleCount() > N_MIN_TRIA_NEWWAY) bNewWay = true ; } else if ( ( nGeoType & GEO_VOLUME) != 0) { bNewWay = true ; } else if ( nGeoType == EXT_TEXT) { const ISurfTriMesh* pSTM = ( m_nShowText == TXT_FILL ? GetExtText( pGeoObj)->GetAuxSurf() : nullptr) ; if ( pSTM != nullptr && pSTM->GetTriangleCount() > N_MIN_TRIA_NEWWAY) bNewWay = true ; } } ObjEGrGraphics* pGraphics = CreateObjEGrGraphics( nCount, bNewWay) ; if ( pGraphics == nullptr) return false ; pGraphics->SetScene( this) ; pGeoObj->SetObjGraphics( pGraphics) ; } // se la grafica associata non è valida la ricalcolo ObjEGrGraphics* pGraphics = GetObjEGrGraphics( pGeoObj) ; if ( ! pGraphics->IsValid()) { const double ANG_TOL_GRAPH_DEG = 15 ; // se vettore if ( nGeoType == GEO_VECT3D) { // recupero il vettore const IGeoVector3d* pVector = GetGeoVector3d( pGeoObj) ; if ( pVector == nullptr) return false ; // calcolo la grafica pGraphics->Clear() ; pGraphics->AddColor( siObj.colObj) ; int nFactor, nPattern ; if ( iIter.GetStipple( nFactor, nPattern) && nFactor != 0) pGraphics->AddLineStipple( nFactor, nPattern) ; PolyLine PL ; if ( pVector->GetDrawWithArrowHead( 0.1, 10, PL)) pGraphics->AddPolyLine(PL) ; else pGraphics->AddPoint( pVector->GetBase()) ; } // se punto else if ( nGeoType == GEO_PNT3D) { // recupero il punto const IGeoPoint3d* pPoint = GetGeoPoint3d( pGeoObj) ; if ( pPoint == nullptr) return false ; // calcolo la grafica pGraphics->Clear() ; pGraphics->AddColor( siObj.colObj) ; int nFactor, nPattern ; if ( iIter.GetStipple( nFactor, nPattern) && nFactor != 0) pGraphics->AddLineStipple( nFactor, nPattern) ; pGraphics->AddPoint( pPoint->GetPoint()) ; } // se riferimento else if ( nGeoType == GEO_FRAME3D) { // recupero il riferimento const IGeoFrame3d* pFrame = GetGeoFrame3d( pGeoObj) ; if ( pFrame == nullptr) return false ; // aggiorno la grafica (colori speciali) PolyLine plX, plY, plZ ; pFrame->GetDrawWithArrowHeads( 40, 0.1, plX, plY, plZ) ; pGraphics->Clear() ; pGraphics->AddColor( RED) ; pGraphics->AddPolyLine( plX) ; pGraphics->AddColor( LIME) ; pGraphics->AddPolyLine( plY) ; pGraphics->AddColor( BLUE) ; pGraphics->AddPolyLine( plZ) ; } // se curva else if ( ( nGeoType & GEO_CURVE) != 0) { // recupero la curva const ICurve* pCurve = GetCurve( pGeoObj) ; if ( pCurve == nullptr) return false ; // calcolo la grafica PolyLine PL ; pCurve->ApproxWithLines( EPS_SMALL, ANG_TOL_GRAPH_DEG, ICurve::APL_SPECIAL, PL) ; pGraphics->Clear() ; pGraphics->AddColor( siObj.colObj) ; int nFactor, nPattern ; if ( iIter.GetStipple( nFactor, nPattern) && nFactor != 0) pGraphics->AddLineStipple( nFactor, nPattern) ; pGraphics->AddPolyLine( PL) ; // eventuali segni ausiliari (mark, frecce, ...) Vector3d vtRef ; if ( ! pCurve->GetExtrusion( vtRef) || vtRef.IsSmall()) vtRef = Z_AX ; PolyLine PLM ; if ( CalcCurveTailMark( vtRef, PL, PLM)) pGraphics->AddPolyLine( PLM, true) ; PolyLine PLA ; if ( CalcCurveTipArrow( vtRef, PL, PLA)) pGraphics->AddPolyLine( PLA, true) ; PNTVECTOR vPnt ; if ( CalcCurveJoints( pCurve, vPnt)) pGraphics->AddPoints( vPnt, true) ; // eventuale spessore double dTh ; Vector3d vtExtr ; if ( pCurve->GetExtrusion( vtExtr) && ! vtExtr.IsSmall() && pCurve->GetThickness( dTh) && abs( dTh) > EPS_SMALL) { // segmenti di raccordo PNTVECTOR vPnt ; bool bDense = ( nGeoType == CRV_ARC || nGeoType == CRV_BEZIER) ; if ( CalcCurveConnectingLines( PL, dTh * vtExtr, bDense, vPnt)) pGraphics->AddLines( vPnt) ; // percorso traslato PL.Translate( dTh * vtExtr) ; pGraphics->AddPolyLine( PL) ; } } // se superficie else if ( ( nGeoType & GEO_SURF) != 0) { // recupero la trimesh da visualizzare const ISurfTriMesh* pSTM = GetSurfTriMeshAux( pGeoObj) ; if ( pSTM == nullptr) return false ; // superficie con visualizzazione standard if ( pSTM->GetMaxTFlag() == 0) { // recupero il materiale Material mMat ; if ( ! iIter.GetCalcMaterial( mMat)) mMat.Set( m_colDef) ; // pulisco pGraphics->Clear() ; // se ci sono triangoli int nTria = pSTM->GetTriangleCount() ; if ( nTria > 0) { // assegno i materiali pGraphics->AddColor( siObj.colObj) ; // per wireframe pGraphics->AddMaterial( mMat.GetAmbient(), mMat.GetDiffuse(), mMat.GetSpecular(), mMat.GetShininess()) ; pGraphics->AddBackMaterial( GetSurfBackColor( mMat.GetDiffuse())) ; // ciclo sui triangoli della superficie pGraphics->StartTriangles( nTria) ; Triangle3dEx Tria ; int nId = pSTM->GetFirstTriangle( Tria) ; while ( nId != SVT_NULL) { // se visualizzazione avanzata : edge solo se boundary e normali ai vertici smussate if ( m_bShowTriaAdvanced) pGraphics->AddTriangle( Tria, Tria.GetTriFlags(), Tria.GetTriNormals()) ; // altrimenti : tutti gli edge e normali ai vertici prendono quella del triangolo else pGraphics->AddTriangle( Tria, TriFlags3d(), TriNormals3d( Tria.GetN())) ; nId = pSTM->GetNextTriangle( nId, Tria) ; } pGraphics->EndTriangles() ; } } // altrimenti superficie con due colori else { // numero di colori const int STM_COL = 2 ; // definizione materiali Material mMat[STM_COL] ; Color cCol[STM_COL] ; // recupero il materiale principale cCol[0] = siObj.colObj ; if ( ! iIter.GetCalcMaterial( mMat[0])) mMat[0].Set( m_colDef) ; // secondo materiale per parti modificate (tonalità spostata di +22.5 deg) cCol[1] = cCol[0] ; mMat[1] = mMat[0] ; HSV hsv = GetHSVFromColor( siObj.colObj) ; if ( hsv.dSat > EPS_ZERO) hsv.dHue += ANG_RIGHT / 4 ; else hsv.dVal = 1 - hsv.dVal ; cCol[1] = GetColorFromHSV( hsv) ; mMat[1].Set( cCol[1]) ; // conto i triangoli per tipo (TFlag == 0 e altri) int nTri[STM_COL] = { 0, 0} ; nTri[0] = pSTM->GetTriangleCount( 0) ; nTri[1] = pSTM->GetTriangleCount() - nTri[0] ; // Ciclo sui colori for ( int j = 0 ; j < STM_COL ; ++ j) { // Imposto indice blocco corrente pGraphics->SetCurrent( j) ; // lo pulisco pGraphics->Clear() ; // se non ci sono triangoli, passo oltre if ( nTri[j] == 0) continue ; // assegno materiali pGraphics->AddColor( cCol[j]) ; // per wireframe pGraphics->AddMaterial( mMat[j].GetAmbient(), mMat[j].GetDiffuse(), mMat[j].GetSpecular(), mMat[j].GetShininess()) ; pGraphics->AddBackMaterial( GetSurfBackColor( mMat[j].GetDiffuse())) ; // ciclo sui triangoli della superficie pGraphics->StartTriangles( nTri[j]) ; Triangle3dEx Tria ; int nId = pSTM->GetFirstTriangle( Tria) ; while ( nId != SVT_NULL) { if ( ( j == 0 && Tria.GetGrade() == 0) || ( j == 1 && Tria.GetGrade() != 0)) { // se visualizzazione avanzata : edge solo se boundary e normali ai vertici smussate if ( m_bShowTriaAdvanced) pGraphics->AddTriangle( Tria, Tria.GetTriFlags(), Tria.GetTriNormals()) ; // altrimenti : tutti gli edge e normali ai vertici prendono quella del triangolo else pGraphics->AddTriangle( Tria, TriFlags3d(), TriNormals3d( Tria.GetN())) ; } nId = pSTM->GetNextTriangle( nId, Tria) ; } pGraphics->EndTriangles() ; } } } // se Zmap else if ( nGeoType == VOL_ZMAP) { // recupero il solido Zmap const IVolZmap* pZmap = GetVolZmap( pGeoObj) ; if ( pZmap == nullptr) return false ; // numero di blocchi int nCount = 0 ; // numero di colori const int ZMAP_COL = 2 ; // indicazione se tridexel bool bIsTriDexel = pZmap->IsTriDexel() ; // se triangoli da disegnare if ( ( m_nShowZmap & ZSM_SURF) != 0) { // definizione materiali Material mMat[ZMAP_COL] ; Color cCol[ZMAP_COL] ; // recupero il materiale principale cCol[0] = siObj.colObj ; if ( ! iIter.GetCalcMaterial( mMat[0])) mMat[0].Set( m_colDef) ; // secondo materiale per parti lavorate (tonalità spostata di +22.5 deg) cCol[1] = cCol[0] ; mMat[1] = mMat[0] ; // se richiesto diverso if ( ( m_nShowZmap & ZSM_COLORS) != 0) { HSV hsv = GetHSVFromColor( siObj.colObj) ; if ( hsv.dSat > EPS_ZERO) hsv.dHue += ANG_RIGHT / 4 ; else hsv.dVal = 1 - hsv.dVal ; cCol[1] = GetColorFromHSV( hsv) ; mMat[1].Set( cCol[1]) ; } // Ciclo sui blocchi nCount = pZmap->GetBlockCount() ; for ( int i = 0 ; i < nCount ; ++ i) { // Se blocco già aggiornato, vado oltre pGraphics->SetCurrent( ZMAP_COL * i) ; if ( pZmap->GetBlockUpdatingCounter( i) <= pGraphics->GetCounter()) continue ; // Recupero i triangoli del blocco TRIA3DEXVECTOR vTria ; pZmap->GetBlockTriangles( i, vTria) ; // conto i triangoli per tipo (Flag == 0 e altri) int nTri[ZMAP_COL] = { 0, 0} ; for ( const auto& Tria : vTria) { if ( Tria.GetGrade() == 0) ++ nTri[0] ; else ++ nTri[1] ; } // Ciclo sui colori for ( int j = 0 ; j < ZMAP_COL ; ++ j) { // Imposto indice blocco corrente pGraphics->SetCurrent( ZMAP_COL * i + j) ; // lo pulisco pGraphics->Clear() ; // se non ci sono triangoli, passo oltre if ( nTri[j] == 0) continue ; // assegno materiali pGraphics->AddColor( cCol[j]) ; // per wireframe pGraphics->AddMaterial( mMat[j].GetAmbient(), mMat[j].GetDiffuse(), mMat[j].GetSpecular(), mMat[j].GetShininess()) ; pGraphics->AddBackMaterial( GetSurfBackColor( mMat[j].GetDiffuse())) ; // passo i triangoli alla grafica pGraphics->StartTriangles( nTri[j]) ; for ( const auto& Tria : vTria) { if ( ( j == 0 && Tria.GetGrade() != 0) || ( j == 1 && Tria.GetGrade() == 0)) continue ; if ( m_bShowTriaAdvanced && bIsTriDexel) pGraphics->AddTriangle( Tria, Tria.GetTriFlags(), Tria.GetTriNormals()) ; else pGraphics->AddTriangle( Tria, TriFlags3d(), TriNormals3d( Tria.GetN())) ; } pGraphics->EndTriangles() ; // assegno contatore di aggiornamenti pGraphics->SetCounter( pZmap->GetBlockUpdatingCounter( i)) ; } } } // visualizzazione spilloni e normali (sempre nell'ultimo blocco) if ( ( m_nShowZmap & ZSM_LINES) != 0 || ( m_nShowZmap & ZSM_NORMALS) != 0) { // imposto indice blocco corrente pGraphics->SetCurrent( ZMAP_COL * nCount) ; // lo pulisco pGraphics->Clear() ; // ciclo sui tre gruppi di spilloni int nKmin = ( m_nShowZmap & ZSM_LINES) != 0 ? 0 : 3 ; int nKmax = ( m_nShowZmap & ZSM_NORMALS) != 0 ? 6 : 3 ; Color vCol[6] = {BLUE, RED, GREEN, BLUE, RED, GREEN} ; for ( int k = nKmin ; k < nKmax ; ++ k) { pGraphics->AddColor( vCol[k]) ; pGraphics->AddMaterial( vCol[k], vCol[k], vCol[k], 10) ; pGraphics->AddBackMaterial( vCol[k]) ; PNTVECTOR vPnt ; for ( int i = 0 ; ; ++ i) { bool bOutBreak = false ; for ( int j = 0 ; ; ++ j) { POLYLINELIST lstPL ; if ( pZmap->GetDexelLines( k, j, i, lstPL)) { for ( const auto& PL : lstPL) { Point3d ptS, ptE ; bool Found = PL.GetFirstLine( ptS, ptE) ; while ( Found) { vPnt.emplace_back( ptS) ; vPnt.emplace_back( ptE) ; Found = PL.GetNextLine( ptS, ptE) ; } } } else { if ( j == 0) bOutBreak = true ; break ; } } if ( bOutBreak) break ; } if ( vPnt.size() > 0) pGraphics->AddLines( vPnt) ; } } } // se testo else if ( nGeoType == EXT_TEXT) { // recupero il testo const IExtText* pTXT = GetExtText( pGeoObj) ; if ( pTXT == nullptr) return false ; // calcolo la grafica const ISurfTriMesh* pSTM = ( m_nShowText == TXT_FILL ? pTXT->GetAuxSurf() : nullptr) ; if ( pSTM != nullptr) { // recupero il materiale Material mMat ; if ( ! iIter.GetCalcMaterial( mMat)) mMat.Set( m_colDef) ; // lo pulisco pGraphics->Clear() ; // se ci sono triangoli int nTria = pSTM->GetTriangleCount() ; if ( nTria > 0) { // assegno materiali pGraphics->AddColor( siObj.colObj) ; // per wireframe pGraphics->AddMaterial( mMat.GetAmbient(), mMat.GetDiffuse(), mMat.GetSpecular(), mMat.GetShininess()) ; pGraphics->AddBackMaterial( GetSurfBackColor( mMat.GetDiffuse())) ; // ciclo sui triangoli della superficie pGraphics->StartTriangles( nTria) ; Triangle3dEx Tria ; int nId = pSTM->GetFirstTriangle( Tria) ; while ( nId != SVT_NULL) { // se visualizzazione avanzata : edge solo se boundary e normali ai vertici smussate if ( m_bShowTriaAdvanced) pGraphics->AddTriangle( Tria, Tria.GetTriFlags(), Tria.GetTriNormals()) ; // altrimenti : tutti gli edge e normali ai vertici prendono quella del triangolo else pGraphics->AddTriangle( Tria, TriFlags3d(), TriNormals3d( Tria.GetN())) ; nId = pSTM->GetNextTriangle( nId, Tria) ; } pGraphics->EndTriangles() ; } } else { POLYLINELIST lstPL ; pTXT->ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_GRAPH_DEG, lstPL) ; pGraphics->Clear() ; pGraphics->AddColor( siObj.colObj) ; for ( const auto& PL : lstPL) pGraphics->AddPolyLine( PL) ; } } // se quota else if ( nGeoType == EXT_DIMENSION) { // recupero la quota const IExtDimension* pDim = GetExtDimension( pGeoObj) ; if ( pDim == nullptr) return false ; // calcolo la grafica POLYLINELIST lstPL ; pDim->ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_GRAPH_DEG, lstPL) ; pGraphics->Clear() ; pGraphics->AddColor( siObj.colObj) ; for ( const auto& PL : lstPL) pGraphics->AddPolyLine( PL) ; } // se esiste parte custom if ( pUserObj != nullptr) { POLYLINELIST lstPL ; if ( pUserObj->GetDrawPolyLines( lstPL)) { for ( const auto& PL : lstPL) pGraphics->AddPolyLine( PL, ( PL.GetTempProp() == 0)) ; } } } // se richiesto, visualizzo la grafica associata bool bShowAux = false ; if ( (( nGeoType & GEO_CURVE) != 0 || pUserObj != nullptr) && m_bShowCurveDirection) bShowAux = true ; // verifico se oggetto con superficie bool bSurf = (( nGeoType & ( GEO_SURF | GEO_VOLUME)) != 0) ; bool bGenSurf = ( bSurf || ( nGeoType == EXT_TEXT && m_nShowText == TXT_FILL && GetExtText( pGeoObj)->GetAuxSurf() != nullptr)) ; // recupero il valore di opacità (solo per le superfici e i solidi può esserci trasparenza) int nAlpha = siObj.colObj.GetIntAlpha() ; // salto in ogni caso le superfici e i solidi completamente trasparenti if ( nAlpha == 0 && bGenSurf) return true ; // se hiddenline e non selezione if ( m_nShowMode == SM_HIDDENLINE && ! m_bSelect) { // in prima passata disegno solo le superfici opache if ( nPass == 1 && ( ! bGenSurf || nAlpha <= ALPHA_LIM)) return true ; } // se shading e non modalità selezione bool bSurfSha = false ; if ( m_nShowMode == SM_SHADING && ! m_bSelect) { // in prima passata disegno solo le superfici opache e metto in un vettore quelle semitrasparenti if ( nPass == 1) { if ( ! bGenSurf) return true ; else { if ( nAlpha > ALPHA_LIM) bSurfSha = true ; else { // recupero matrice MODELVIEW corrente GLdouble ModelView[ OGLMAT_DIM] ; glGetDoublev( GL_MODELVIEW_MATRIX, ModelView) ; Frame3d frModView ; OpenGlMatrixToFrame( ModelView, frModView) ; // recupero il box dell'oggetto e lo porto nel riferimento MODELVIEW BBox3d b3Box ; pGraphics->GetLocalBBox( b3Box) ; b3Box.ToGlob( frModView) ; // inserisco i dati nel vettore m_vAlphaSurf.emplace_back( frModView, pGraphics, siObj.nStat, siObj.nMark, bSurf, nAlpha, bShowAux, b3Box.GetMin().z, b3Box.GetMax().z) ; return true ; } } } // in seconda passata disegno solo dimensioni 0 e curve if ( nPass == 2 && bGenSurf) return true ; } // se in selezione if ( m_bSelect) { // vaglio per il filtro di tipo if ( ( nGeoType & m_nObjFilterForSelect) == 0) return true ; // carico il nome glLoadName( iIter.GetId()) ; } // eventuale texture string sTxrName ; if ( iIter.GetTextureName( sTxrName)) { // rendo corrente la texture GLuint texName ; double dTextDimS ; double dTextDimT ; if ( m_TextMgr.GetTextureData( sTxrName, texName, dTextDimS, dTextDimT)) { glEnable( GL_TEXTURE_2D) ; glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE) ; glBindTexture( GL_TEXTURE_2D, texName) ; } // se esiste parte custom, eventuale recupero dimensioni aggiornate if ( pUserObj != nullptr) pUserObj->GetDimensions( dTextDimS, dTextDimT) ; // recupero il riferimento della texture Frame3d frTxr ; iIter.GetTextureFrame( frTxr) ; // creo piano per la S GLfloat PlaneS[4] { GLfloat( frTxr.VersX().x / dTextDimS), GLfloat( frTxr.VersX().y / dTextDimS), GLfloat( frTxr.VersX().z / dTextDimS), GLfloat( -frTxr.VersX() * ( frTxr.Orig() - ORIG) / dTextDimS)} ; // creo piano per la T GLfloat PlaneT[4] { GLfloat( frTxr.VersY().x / dTextDimT), GLfloat( frTxr.VersY().y / dTextDimT), GLfloat( frTxr.VersY().z / dTextDimT), GLfloat( -frTxr.VersY() * ( frTxr.Orig() - ORIG) / dTextDimT)} ; // setto generazione automatica coordinate S e T per texture glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR) ; glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR) ; glTexGenfv( GL_S, GL_OBJECT_PLANE, PlaneS) ; glTexGenfv( GL_T, GL_OBJECT_PLANE, PlaneT) ; glEnable( GL_TEXTURE_GEN_S) ; glEnable( GL_TEXTURE_GEN_T) ; } // eseguo visualizzazione bool bOk = pGraphics->Draw( siObj.nStat, siObj.nMark, bSurfSha, bSurf, nAlpha, bShowAux) ; // disabilito textures glDisable( GL_TEXTURE_GEN_S) ; glDisable( GL_TEXTURE_GEN_T) ; glDisable( GL_TEXTURE_2D) ; return bOk ; } //---------------------------------------------------------------------------- bool Scene::DrawAlphaSurfVector( void) { // ordino vettore in senso crescente secondo Zmax (asse Z punta verso osservatore) sort( m_vAlphaSurf.begin(), m_vAlphaSurf.end(), []( const AlphaSurf& a, const AlphaSurf&b) { return a.dZmax < b.dZmax ; }) ; // eseguo visualizzazione for ( const auto& AlphaSurf : m_vAlphaSurf) { // imposto matrice MODELVIEW double Matrix[OGLMAT_DIM] ; FrameToOpenGlMatrix( AlphaSurf.frModView, Matrix) ; glPushMatrix() ; glLoadMatrixd( Matrix) ; // eseguo visualizzazione bool bOk = AlphaSurf.pGraph->Draw( AlphaSurf.nStat, AlphaSurf.nMark, true, AlphaSurf.bSurf, AlphaSurf.nAlpha, AlphaSurf.bShowAux) ; // ripristino matrice glPopMatrix() ; // in caso di errore, esco if ( ! bOk) return false ; } return true ; } //---------------------------------------------------------------------------- bool Scene::DeleteObjGraphicsGroup( int nId) { // creo un iteratore PtrOwner pIter( CreateGdbIterator( m_pGeomDB)) ; if ( IsNull( pIter)) return false ; // scandisco il gruppo bool bNext = pIter->GoToFirstInGroup( nId) ; while ( bNext) { // leggo il tipo di nodo int nGdbType = pIter->GetGdbType() ; // se oggetto geometrico if ( nGdbType == GDB_TY_GEO) { // lo recupero IGeoObj* pGeoObj = pIter->GetGeoObj() ; if ( pGeoObj == nullptr) return false ; // ne cancello l'eventuale parte grafica ObjEGrGraphics* pGraph = GetObjEGrGraphics( pGeoObj) ; if ( pGraph != nullptr && pGraph->GetScene() == this) pGeoObj->SetObjGraphics( nullptr) ; } // se gruppo else if ( nGdbType == GDB_TY_GROUP) { // ripeto sugli oggetti dello stesso if ( ! DeleteObjGraphicsGroup( pIter->GetId())) return false ; } // passo al successivo bNext = pIter->GoToNext() ; } return true ; } //------------------------------ Local functions ----------------------------- //---------------------------------------------------------------------------- static ObjEGrGraphics* CreateObjEGrGraphics( int nCount, bool bNewWay) { if ( nCount > 1) return ( new( nothrow) ObjMultiGraphics( nCount, bNewWay)) ; else if ( bNewWay) return ( new( nothrow) ObjNewGraphics) ; else return ( new( nothrow) ObjOldGraphics) ; } //---------------------------------------------------------------------------- static bool CalcCurveTailMark( const Vector3d& vtRef, const PolyLine& plCrv, PolyLine& plMark) { // pulisco la polilinea per il segno plMark.Clear() ; // verifico effettiva esistenza della polilinea approssimante la curva if ( plCrv.GetLineNbr() < 1) return false ; // dimensioni limite traverso const double MAX_LEN_TR = 6 ; const double MIN_LEN_TR = 0.1 ; // recupero dati primo tratto della curva Point3d ptTail, ptP ; if ( ! plCrv.GetFirstLine( ptTail, ptP)) return false ; Vector3d vtDir = ptP - ptTail ; double dLen = vtDir.Len() ; if ( dLen < EPS_SMALL) return false ; vtDir /= dLen ; // se molto piccolo, cerco di allungarmi senza deviare troppo while ( dLen < MAX_LEN_TR) { Point3d ptP1, ptP2 ; if ( ! plCrv.GetNextLine( ptP1, ptP2)) break ; Vector3d vtNxDir = ptP2 - ptP1 ; vtNxDir.Normalize() ; if ( ( vtDir * vtNxDir) > cos( 30 * DEGTORAD)) dLen = (ptP1 - ptTail).Len() ; else break ; } // recupero lunghezza del percorso double dLenRef = 0 ; plCrv.GetApproxLength( dLenRef) ; // lunghezza della freccia // calcolo dimensioni traverso const double TR_COEFF = 0.6 ; const double LEN_COEFF = 0.15 ; double dLenTr = TR_COEFF * min( LEN_COEFF * dLenRef, dLen) ; if ( dLenTr > MAX_LEN_TR) dLenTr = MAX_LEN_TR ; else if ( dLenTr < MIN_LEN_TR) dLenTr = MIN_LEN_TR ; // disegno traverso Frame3d frF ; if ( frF.Set( ptTail, vtDir, vtRef)) { Point3d ptP0 = GetToGlob( ORIG + Vector3d( 0, 0.5 * dLenTr, 0), frF) ; plMark.AddUPoint( 0, ptP0) ; Point3d ptP1 = GetToGlob( ORIG + Vector3d( 0, - 0.5 * dLenTr, 0), frF) ; plMark.AddUPoint( 1, ptP1) ; } else { frF.Set( ptTail, vtDir) ; Point3d ptP0 = GetToGlob( ORIG + Vector3d( - 0.5 * dLenTr, - 0.5 * dLenTr, 0), frF) ; plMark.AddUPoint( 0, ptP0) ; Point3d ptP1 = GetToGlob( ORIG + Vector3d( 0.5 * dLenTr, - 0.5 * dLenTr, 0), frF) ; plMark.AddUPoint( 1, ptP1) ; Point3d ptP2 = GetToGlob( ORIG + Vector3d( 0.5 * dLenTr, 0.5 * dLenTr, 0), frF) ; plMark.AddUPoint( 2, ptP2) ; Point3d ptP3 = GetToGlob( ORIG + Vector3d( - 0.5 * dLenTr, 0.5 * dLenTr, 0), frF) ; plMark.AddUPoint( 3, ptP3) ; // punto di chiusura coincidente con il primo plMark.AddUPoint( 4, ptP0) ; } return true ; } //---------------------------------------------------------------------------- static bool CalcCurveTipArrow( const Vector3d& vtRef, const PolyLine& plCrv, PolyLine& plArr) { // pulisco la polilinea per la freccia plArr.Clear() ; // verifico effettiva esistenza della polilinea approssimante la curva if ( plCrv.GetLineNbr() < 1) return false ; // dimensioni freccia limite const double MAX_LEN_ARR = 10.0 ; const double MIN_LEN_ARR = 0.1 ; // recupero dati ultimo tratto della curva Point3d ptTip, ptP ; if ( ! plCrv.GetLastLine( ptP, ptTip)) return false ; Vector3d vtDir = ptTip - ptP ; double dLen = vtDir.Len() ; if ( dLen < EPS_SMALL) return false ; vtDir /= dLen ; // se molto piccolo, cerco di allungarmi senza deviare troppo while ( dLen < MAX_LEN_ARR) { Point3d ptP1, ptP2 ; if ( ! plCrv.GetPrevLine( ptP1, ptP2)) break ; Vector3d vtPrDir = ptP2 - ptP1 ; vtPrDir.Normalize() ; if ( ( vtDir * vtPrDir) > cos( 30 * DEGTORAD)) dLen = (ptTip - ptP1).Len() ; else break ; } // recupero lunghezza del percorso double dLenRef = 0 ; plCrv.GetApproxLength( dLenRef) ; // lunghezza della freccia const double LEN_COEFF = 0.15 ; double dLenArr = min( LEN_COEFF * dLenRef, dLen) ; if ( dLenArr > MAX_LEN_ARR) dLenArr = MAX_LEN_ARR ; else if ( dLenArr < MIN_LEN_ARR) dLenArr = MIN_LEN_ARR ; // disegno freccia const double A_WIDTH_COEFF = 0.3 ; Frame3d frF ; if ( ! frF.Set( ptTip, vtDir, vtRef)) frF.Set( ptTip, vtDir) ; plArr.AddUPoint( 0, ptTip) ; Point3d ptP1 = GetToGlob( ORIG + Vector3d( 0, A_WIDTH_COEFF, -1) * dLenArr, frF) ; plArr.AddUPoint( 1, ptP1) ; Point3d ptP2 = GetToGlob( ORIG + Vector3d( 0, - A_WIDTH_COEFF, -1) * dLenArr, frF) ; plArr.AddUPoint( 2, ptP2) ; plArr.AddUPoint( 3, ptTip) ; return true ; } //---------------------------------------------------------------------------- static bool CalcCurveConnectingLines( const PolyLine& plCrv, const Vector3d& vtTh, bool bDense, PNTVECTOR& vPnt) { // assegno coefficiente double dDelta = ( bDense ? 0.25 : 0.5) ; // ciclo per creare i segmenti di raccordo double dU, dUprev = - dDelta ; vPnt.reserve( 5) ; for ( bool bFound = plCrv.GetFirstU( dU) ; bFound ; bFound = plCrv.GetNextU( dU)) { if ( ( dU - dUprev) > dDelta - EPS_PARAM || fmod( dU, 1.) < EPS_PARAM) { Point3d ptP ; plCrv.GetCurrPoint( ptP) ; vPnt.push_back( ptP) ; ptP += vtTh ; vPnt.push_back( ptP) ; dUprev = dU ; } } return true ; } //---------------------------------------------------------------------------- static bool CalcCurveJoints( const ICurve* pCurve, PNTVECTOR& vPnt) { // pulisco il vettore dei punti vPnt.clear() ; // recupero il dominio della curva double dParS = 0, dParE = 1 ; pCurve->GetDomain( dParS, dParE) ; // recupero i punti intermedi for ( double dPar = dParS + 1 ; dPar < dParE - EPS_PARAM ; dPar += 1) { Point3d ptP ; if ( pCurve->GetPointD1D2( dPar, ICurve::FROM_MINUS, ptP)) vPnt.push_back( ptP) ; } return true ; }