//---------------------------------------------------------------------------- // EgalTech 2013-2014 //---------------------------------------------------------------------------- // File : SceneSelect.cpp Data : 26.11.14 Versione : 1.5k5 // Contenuto : Implementazione della selezione nella scena. // // // // Modifiche : 26.11.14 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "Scene.h" #include "GraphObjs.h" #include "ObjEGrGraphics.h" #include "DllMain.h" #include "/EgtDev/Include/EGkGeoPoint3d.h" #include "/EgtDev/Include/EGkGeoVector3d.h" #include "/EgtDev/Include/EGkFrame3d.h" #include "/EgtDev/Include/EGkCurve.h" #include "/EgtDev/Include/EGkDistPointCurve.h" #include "/EgtDev/Include/EGkSurfTriMesh.h" #include "/EgtDev/Include/EGkSurfFlatRegion.h" #include "/EgtDev/Include/EGkSurfBezier.h" #include "/EgtDev/Include/EGkExtText.h" #include "/EgtDev/Include/EGkExtDimension.h" #include "/EgtDev/Include/EGkIntersLinePlane.h" #include "/EgtDev/Include/EGkIntersLineSurfTm.h" #include "/EgtDev/Include/EGkGdbConst.h" #include "/EgtDev/Include/EGkGeomDB.h" #include using namespace std ; //---------------------------------------------------------------------------- int CompareSelRec( const void* pSr1, const void* pSr2) { if ( ((SelRec*)pSr1)->nZmin > ((SelRec*)pSr2)->nZmin) return 1 ; else if ( ((SelRec*)pSr1)->nZmin < ((SelRec*)pSr2)->nZmin) return - 1 ; else { if ( ((SelRec*)pSr1)->nId > ((SelRec*)pSr2)->nId) return 1 ; else if ( ((SelRec*)pSr1)->nId < ((SelRec*)pSr2)->nId) return - 1 ; else return 0 ; } } //---------------------------------------------------------------------------- bool Scene::Select( const Point3d& ptSelCenter, int nW, int nH, int& nSel) { // inizializzo selezione m_bSelect = true ; m_ptSelCent = ptSelCenter ; m_nSelW = abs( nW) ; m_nSelH = abs( nH) ; m_nSelNbr = 0 ; // se una delle due dimensioni è nulla, non posso selezionare alcunché if ( m_nSelW == 0 || m_nSelH == 0) { m_bSelect = false ; nSel = m_nSelNbr ; return true ; } // sfondo e Zbuffer non interessano // imposto la camera, riducendo la viewport all'area di selezione if ( ! Prepare()) { m_bSelect = false ; nSel = m_nSelNbr ; return false ; } // imposto modalità di selezione glSelectBuffer( SIZE_SEL_BUF, (GLuint*)m_nSelBuff) ; glRenderMode( GL_SELECT) ; // inizializzo stack dei nomi glInitNames() ; glPushName( 0) ; // eseguo disegno // disabilito illuminazione glDisable( GL_LIGHTING) ; // non imposto glPolygonMode secondo il tipo di rendering perchè ignorato in selezione // disegno le geometrie del DB in una sola passata DrawGroup( GDB_ID_ROOT, 1, MdStMkCol( GDB_MD_STD, GDB_ST_ON, GDB_MK_OFF, m_colDef)) ; // pulisco stack nomi glPopName() ; // chiudo modalità selezione, recupero buffer ripristino le matrici di OpenGL m_nSelNbr = glRenderMode( GL_RENDER) ; if ( m_nSelNbr < 0) m_nSelNbr = DIM_SEL_BUF ; m_bSelect = false ; Prepare() ; // riordino il buffer di selezione secondo la Zdepth minima crescente qsort( m_nSelBuff, m_nSelNbr, sizeof( SelRec), CompareSelRec) ; nSel = m_nSelNbr ; return true ; } //---------------------------------------------------------------------------- bool Scene::SetObjFilterForSelect( bool bZerodim, bool bCurve, bool bSurf, bool bVolume, bool bExtra) { m_nObjFilterForSelect = 0 ; if ( bZerodim) m_nObjFilterForSelect |= GEO_ZERODIM ; if ( bCurve) m_nObjFilterForSelect |= GEO_CURVE ; if ( bSurf) m_nObjFilterForSelect |= GEO_SURF ; if ( bVolume) m_nObjFilterForSelect |= GEO_VOLUME ; if ( bExtra) m_nObjFilterForSelect |= GEO_EXTRA ; return true ; } //---------------------------------------------------------------------------- bool Scene::GetSelectedObjs( INTVECTOR& nIds) const { // inizializzo vettore Id nIds.clear() ; try { nIds.reserve( m_nSelNbr) ; } catch(...) { return false ; } // inserisco l'Id degli oggetti selezionati for ( int i = 0 ; i < m_nSelNbr ; ++ i) nIds.push_back( m_nSelBuff[i].nId) ; return true ; } //---------------------------------------------------------------------------- int Scene::GetFirstSelectedObj( void) { m_nSelCurr = - 1 ; return GetNextSelectedObj() ; } //---------------------------------------------------------------------------- int Scene::GetNextSelectedObj( void) { // fuori dal range m_nSelCurr ++ ; if ( m_nSelCurr < 0 || m_nSelCurr >= m_nSelNbr) return GDB_ID_NULL ; return m_nSelBuff[m_nSelCurr].nId ; } //---------------------------------------------------------------------------- double Scene::GetSelectedObjWinZ( int nSel) const { if ( nSel < 0) nSel = m_nSelCurr ; if ( nSel < 0 || nSel >= m_nSelNbr) return 0.5 ; return 0.5 * ( double( m_nSelBuff[nSel].nZmin) + double( m_nSelBuff[nSel].nZmax)) / UINT_MAX ; } //---------------------------------------------------------------------------- double Scene::GetSelectedObjMinWinZ( int nSel) const { if ( nSel < 0) nSel = m_nSelCurr ; if ( nSel < 0 || nSel >= m_nSelNbr) return 0.5 ; return ( double( m_nSelBuff[nSel].nZmin)) / UINT_MAX ; } /*------------------------------------------------------------------------------------------*/ bool Scene::UnselectableAdd( int nId) { // non si ammettono radice e id negativi if ( nId <= GDB_ID_ROOT) return false ; // verifico se già presente if ( binary_search( m_Unsel.begin(), m_Unsel.end(), nId)) return true ; // inserisco l'elemento m_Unsel.push_back( nId) ; // ordino in senso crescente stable_sort( m_Unsel.begin(), m_Unsel.end()) ; return true ; } /*------------------------------------------------------------------------------------------*/ bool Scene::UnselectableRemove( int nId) { // non si ammettono radice e id negativi if ( nId <= GDB_ID_ROOT) return false ; // cerco l'elemento INTVECTOR::iterator Iter = find( m_Unsel.begin(), m_Unsel.end(), nId) ; if ( Iter == m_Unsel.end()) return true ; m_Unsel.erase( Iter) ; return true ; } /*------------------------------------------------------------------------------------------*/ bool Scene::UnselectableClearAll( void) { // cancello tutto m_Unsel.clear() ; return true ; } /*------------------------------------------------------------------------------------------*/ bool Scene::UnselectableFind( int nId) { // eseguo ricerca su vettore ordinato in senso crescente return binary_search( m_Unsel.begin(), m_Unsel.end(), nId) ; } /*------------------------------------------------------------------------------------------*/ bool Scene::GetPointFromSelect( int nSelId, const Point3d& ptView, Point3d& ptSel, int& nAux) { // recupera il punto di mira proiettato sull'oggetto appena selezionato // (va eseguito subito dopo la Select da cui si è derivato l'Id) // è simile a FindSelectedSnapPoint // verifico parametri di ritorno if ( &ptSel == nullptr || &nAux == nullptr) return false ; // rendo corrente l'entità selezionata bool bFound = false ; for ( int nId = GetFirstSelectedObj() ; nId != GDB_ID_NULL ; nId = GetNextSelectedObj()) { if ( nId == nSelId) { bFound = true ; break ; } } if ( ! bFound) return false ; // verifico sia entità geometrica const IGeoObj* pGObj ; if ( ( pGObj = m_pGeomDB->GetGeoObj( nSelId)) == nullptr) return false ; // recupero riferimento dell'entità Frame3d frEnt ; if ( ! m_pGeomDB->GetGlobFrame( nSelId, frEnt)) return false ; // inizializzo indice ausiliario (Id del sotto-oggetto : curva semplice o triangolo) nAux = 0 ; // se punto if ( pGObj->GetType() == GEO_PNT3D) { // recupero il geo-punto const IGeoPoint3d* pGP = GetGeoPoint3d( pGObj) ; // recupero il punto ptSel = GetToGlob( pGP->GetPoint(), frEnt) ; } // se vettore else if ( pGObj->GetType() == GEO_VECT3D) { // recupero il geo-vettore const IGeoVector3d* pGV = GetGeoVector3d( pGObj) ; // recupero il punto ptSel = GetToGlob( pGV->GetBase(), frEnt) ; } // se frame else if ( pGObj->GetType() == GEO_FRAME3D) { // recupero il geo-frame const IGeoFrame3d* pGF = GetGeoFrame3d( pGObj) ; // recupero il punto ptSel = GetToGlob( pGF->GetFrame().Orig(), frEnt) ; } // se curva else if ( ( pGObj->GetType() & GEO_CURVE) != 0) { // recupero la curva const ICurve* pCrv = GetCurve( pGObj) ; // il punto di riferimento deriva da XY su viewport e Z da selezione Point3d ptWinZ( ptView.x, ptView.y, GetSelectedObjWinZ()) ; // lo porto da spazio grafico a spazio geometrico globale Point3d ptRef ; UnProject( ptWinZ, ptRef) ; // lo porto nel frame della curva ptRef.ToLoc( frEnt) ; // determino il punto più vicino della curva a questo double dMinSqDist = INFINITO * INFINITO ; MinDistPCInfo mdInfo ; DistPointCurve dstPtCurve( ptRef, *pCrv) ; if ( dstPtCurve.GetMinDistInfo( 0, mdInfo)) { Point3d ptP = GetToGlob( mdInfo.ptQ, frEnt) ; if ( VerifySnapPoint( ptP, ptView, dMinSqDist)) { ptSel = ptP ; nAux = int( mdInfo.dPar) ; } } // eventuale verifica dell'estruso double dTh ; Vector3d vtExtr ; if ( pCrv->GetExtrusion( vtExtr) && ! vtExtr.IsSmall() && pCrv->GetThickness( dTh) && abs( dTh) > EPS_SMALL) { vtExtr *= dTh ; vtExtr.ToGlob( frEnt) ; // correggo il punto di riferimento del contrario dell'estrusione Vector3d vtTemp = GetToLoc( vtExtr, frEnt) ; // determino il punto più vicino della curva a questo MinDistPCInfo mdInfo ; DistPointCurve dstPtCurve( ptRef - vtTemp, *pCrv) ; if ( dstPtCurve.GetMinDistInfo( 0, mdInfo)) { Point3d ptP = GetToGlob( mdInfo.ptQ, frEnt) ; ptP += vtExtr ; if ( VerifySnapPoint( ptP, ptView, dMinSqDist)) { ptSel = ptP ; nAux = int( mdInfo.dPar) ; } } } } // se superficie trimesh else if ( pGObj->GetType() == SRF_TRIMESH) { // recupero la superficie const ISurfTriMesh* pStm = GetSurfTriMesh( pGObj) ; // il punto di riferimento deriva da XY su viewport e Z da selezione Point3d ptWinZ( ptView.x, ptView.y, GetSelectedObjWinZ()) ; // lo porto da spazio grafico a spazio geometrico globale Point3d ptRef ; UnProject( ptWinZ, ptRef) ; // lo porto nel frame della superficie ptRef.ToLoc( frEnt) ; // recupero la direzione di mira e la porto nel riferimento della superficie Vector3d vtDir = GetToLoc( -m_vtDirCamera, frEnt) ; // recupero il raggio del box di ingombro double dBlRad = 1000 ; const ObjEGrGraphics* pGraphics = GetObjEGrGraphics( pStm) ; if ( pGraphics != nullptr) { BBox3d b3Loc ; if ( pGraphics->GetLocalBBox( b3Loc)) b3Loc.GetRadius( dBlRad) ; } // punto davanti all'oggetto lungo il raggio di mira Point3d ptMir = ptRef - vtDir * 2 * dBlRad ; double dLenMir = 4 * dBlRad ; // cerco i triangoli intersecati dalla linea di mira ILSIVECTOR vInfo ; if ( ! IntersLineSurfTm( ptMir, vtDir, dLenMir, *pStm, vInfo) || vInfo.size() == 0) return false ; // recupero il primo punto ptSel = GetToGlob( vInfo[0].ptI, frEnt) ; nAux = vInfo[0].nT ; } // se regione else if ( pGObj->GetType() == SRF_FLATRGN) { // recupero la regione const ISurfFlatRegion* pReg = GetSurfFlatRegion( pGObj) ; // il punto di riferimento deriva da XY su viewport e Z da selezione Point3d ptWinZ( ptView.x, ptView.y, GetSelectedObjWinZ()) ; // lo porto da spazio grafico a spazio geometrico globale Point3d ptRef ; UnProject( ptWinZ, ptRef) ; // lo porto nel frame della regione ptRef.ToLoc( frEnt) ; // recupero la direzione di mira e la porto nel riferimento della regione Vector3d vtDir = GetToLoc( -m_vtDirCamera, frEnt) ; // recupero il piano della regione Plane3d plReg ; plReg.Set( pReg->GetPlanePoint(), pReg->GetNormVersor()) ; // interseco la linea di mira con il piano della regione Point3d ptInt ; if ( IntersLinePlane( ptRef, vtDir, INFINITO, plReg, ptInt, false) != ILPT_YES) return false ; // assegno il punto ptSel = GetToGlob( ptInt, frEnt) ; // determino il chunk nAux = 0 ; if ( pReg->GetChunkCount() > 1) { // verifico a quale contorno esterno di chunk è più vicino (potrebbe essere appena fuori dal bordo il centro del mirino) double dMinSqDist = INFINITO * INFINITO ; for ( int nC = 0 ; nC < pReg->GetChunkCount() ; ++ nC) { PtrOwner pCrv( pReg->GetLoop( nC, 0)) ; if ( IsNull( pCrv)) return false ; double dSqDist ; if ( DistPointCurve( ptInt, *pCrv).GetSqDist( dSqDist) && dSqDist < dMinSqDist) { nAux = nC ; dMinSqDist = dSqDist ; } } } } // se superficie di Bezier else if ( pGObj->GetType() == SRF_BEZIER) { // recupero la superficie const ISurfBezier* pSbz = GetSurfBezier( pGObj) ; const ISurfTriMesh* pStm = pSbz->GetAuxSurf() ; // il punto di riferimento deriva da XY su viewport e Z da selezione Point3d ptWinZ( ptView.x, ptView.y, GetSelectedObjWinZ()) ; // lo porto da spazio grafico a spazio geometrico globale Point3d ptRef ; UnProject( ptWinZ, ptRef) ; // lo porto nel frame della superficie ptRef.ToLoc( frEnt) ; // recupero la direzione di mira e la porto nel riferimento della superficie Vector3d vtDir = GetToLoc( -m_vtDirCamera, frEnt) ; // recupero il raggio del box di ingombro double dBlRad = 1000 ; const ObjEGrGraphics* pGraphics = GetObjEGrGraphics( pStm) ; if ( pGraphics != nullptr) { BBox3d b3Loc ; if ( pGraphics->GetLocalBBox( b3Loc)) b3Loc.GetRadius( dBlRad) ; } // punto davanti all'oggetto lungo il raggio di mira Point3d ptMir = ptRef - vtDir * 2 * dBlRad ; double dLenMir = 4 * dBlRad ; // cerco i triangoli intersecati dalla linea di mira ILSIVECTOR vInfo ; if ( ! IntersLineSurfTm( ptMir, vtDir, dLenMir, *pStm, vInfo) || vInfo.size() == 0) return false ; // recupero il primo punto ptSel = GetToGlob( vInfo[0].ptI, frEnt) ; nAux = 0 ; } // se testo else if ( pGObj->GetType() == EXT_TEXT) { // recupero il testo const IExtText* pTxt = GetExtText( pGObj) ; // cerco il punto double dMinSqDist = INFINITO * INFINITO ; Point3d ptP ; // punto iniziale if ( pTxt->GetStartPoint( ptP)) { ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptView, dMinSqDist)) ptSel = ptP ; } // punto sopra iniziale if ( pTxt->GetOverStartPoint( ptP)) { ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptView, dMinSqDist)) ptSel = ptP ; } // punto finale if ( pTxt->GetEndPoint( ptP)) { ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptView, dMinSqDist)) ptSel = ptP ; } // punto sopra finale if ( pTxt->GetOverEndPoint( ptP)) { ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptView, dMinSqDist)) ptSel = ptP ; } // punto medio if ( pTxt->GetMidPoint( ptP)) { ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptView, dMinSqDist)) ptSel = ptP ; } // centro if ( pTxt->GetCenterPoint( ptP)) { ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptView, dMinSqDist)) ptSel = ptP ; } } // se quotatura else if ( pGObj->GetType() == EXT_DIMENSION) { // recupero la quotatura const IExtDimension* pDim = GetExtDimension( pGObj) ; // verifico sia valida if ( pDim->IsValid()) { // cerco il punto double dMinSqDist = INFINITO * INFINITO ; Point3d ptP ; // punto iniziale ptP = GetToGlob( pDim->GetStart(), frEnt) ; if ( VerifySnapPoint( ptP, ptView, dMinSqDist)) ptSel = ptP ; // punto sopra iniziale ptP = GetToGlob( pDim->GetOverStart(), frEnt) ; if ( VerifySnapPoint( ptP, ptView, dMinSqDist)) ptSel = ptP ; // punto finale ptP = GetToGlob( pDim->GetEnd(), frEnt) ; if ( VerifySnapPoint( ptP, ptView, dMinSqDist)) ptSel = ptP ; // punto sopra finale ptP = GetToGlob( pDim->GetOverEnd(), frEnt) ; if ( VerifySnapPoint( ptP, ptView, dMinSqDist)) ptSel = ptP ; // punto medio if ( pDim->GetMidPoint( ptP)) { ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptView, dMinSqDist)) ptSel = ptP ; } // centro if ( pDim->GetCenterPoint( ptP)) { ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptView, dMinSqDist)) ptSel = ptP ; } } } return true ; }