//---------------------------------------------------------------------------- // EgalTech 2014-2014 //---------------------------------------------------------------------------- // File : SceneSnap.cpp Data : 09.10.14 Versione : 1.5j1 // Contenuto : Implementazione snap di punti trmite selezione. // // // // Modifiche : 09.10.14 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "Scene.h" #include "/EgtDev/Include/EGkGeomDB.h" #include "/EgtDev/Include/EgkGeoPoint3d.h" #include "/EgtDev/Include/EgkGeoVector3d.h" #include "/EgtDev/Include/EGkFrame3d.h" #include "/EgtDev/Include/EGkCurve.h" #include "/EgtDev/Include/EGkCurveComposite.h" #include "/EgtDev/Include/EGkDistPointCurve.h" #include "/EgtDev/Include/EGkExtText.h" #include "/EgtDev/Include/EgkIntersCurveCurve.h" #include "/EgtDev/Include/EgtPointerOwner.h" using namespace std ; //---------------------------------------------------------------------------- bool Scene::GetGraphicSnapPoint( int nSnap, const Point3d& ptWin, int nW, int nH, Point3d& ptSel) { // reset dati associati a ultimo punto snap m_nLastSnapId = GDB_ID_NULL ; m_bLastSnapDirOk = false ; // verifico validità GDB if ( m_pGeomDB == nullptr) return false ; // se Snap Sketch o Grid, devo trovare il punto sulla griglia if ( nSnap == SP_SKETCH || nSnap == SP_GRID) return GetGridSnapPoint( ( nSnap == SP_SKETCH), ptWin, ptSel) ; // se Snap Intersection, devo trovare l'intersezione tra due entità inquadrate else if ( nSnap == SP_INTERS) return GetSelectedIntersectionPoint( ptWin, nW, nH, ptSel) ; // altrimenti devo trovare il punto dall'entità inquadrata else return GetSelectedSnapPoint( nSnap, ptWin, nW, nH, ptSel) ; } //---------------------------------------------------------------------------- bool Scene::GetGridSnapPoint( bool bSketch, const Point3d& ptWin, Point3d& ptSel) { // recupero il riferimento di griglia Frame3d frGrid = GetGridFrame() ; // calcolo un punto e la direzione della linea di mira Point3d ptLine ; if ( ! UnProject( ptWin, ptLine)) return false ; Vector3d vtLine = - m_vtDirCamera ; // determino l'intersezione di questa linea con il piano della griglia double dDenom = vtLine * frGrid.VersZ() ; if ( fabs( dDenom) < COS_ORTO_ANG_SMALL) return false ; double dU = ( ( frGrid.Orig() - ptLine) * frGrid.VersZ()) / dDenom ; ptSel = ptLine + dU * vtLine ; // porto il punto sul piano di griglia ptSel.ToLoc( frGrid) ; // se punto grid, devo arrotondare al nodo di griglia più vicino if ( ! bSketch) { ptSel.x = floor( ptSel.x / m_dSnapStep + 0.5) * m_dSnapStep ; ptSel.y = floor( ptSel.y / m_dSnapStep + 0.5) * m_dSnapStep ; } // il punto deve stare sulla griglia ptSel.z = 0 ; // lo riporto in globale ptSel.ToGlob( frGrid) ; return true ; } //---------------------------------------------------------------------------- bool Scene::GetGridSnapPointZ( bool bSketch, const Point3d& ptWin, const Point3d& ptGrid, Point3d& ptSel) { // recupero il riferimento di griglia Frame3d frGrid = GetGridFrame() ; // calcolo un punto e la direzione della linea di mira Point3d ptLine ; if ( ! UnProject( ptWin, ptLine)) return false ; Vector3d vtLine = - m_vtDirCamera ; // piano di elevazione : // per il punto di griglia, contenente la perp. alla griglia e più perp. possibile alla direzione di mira Vector3d vtNorm = vtLine - ( vtLine * frGrid.VersZ()) * frGrid.VersZ() ; if ( ! vtNorm.Normalize()) return false ; // determino l'intersezione della linea di mira con il piano di elevazione double dDenom = vtLine * vtNorm ; if ( fabs( dDenom) < COS_ORTO_ANG_SMALL) return false ; double dU = ( ( ptGrid - ptLine) * vtNorm) / dDenom ; Point3d ptNear = ptLine + dU * vtLine ; // proietto il punto sulla linea di elevazione double dDeltaZ = ( ptNear - ptGrid) * frGrid.VersZ() ; if ( ! bSketch) dDeltaZ = floor( dDeltaZ / m_dSnapStep + 0.5) * m_dSnapStep ; ptSel = ptGrid + dDeltaZ * frGrid.VersZ() ; return true ; } //---------------------------------------------------------------------------- bool Scene::GetSelectedSnapPoint( int nSnap, const Point3d& ptWin, int nW, int nH, Point3d& ptSel) { // verifico siano state selezionate delle entità int nSel ; Select( ptWin, nW, nH, nSel) ; if ( nSel <= 0) return false ; // cerco il punto notevole più vicino alla selezione tra le entità selezionate bool bFound = false ; double dMinSqDist = INFINITO * INFINITO ; for ( int nId = GetFirstSelectedObj() ; nId != GDB_ID_NULL ; nId = GetNextSelectedObj()) { // se non è entità geometrica const IGeoObj* pGObj ; if ( ( pGObj = m_pGeomDB->GetGeoObj( nId)) == nullptr) continue ; // recupero riferimento dell'entità Frame3d frEnt ; if ( ! m_pGeomDB->GetGlobFrame( nId, frEnt)) continue ; // se punto if ( pGObj->GetType() == GEO_PNT3D) { // recupero il geo-punto const IGeoPoint3d* pGP = GetGeoPoint3d( pGObj) ; // recupero il punto Point3d ptP = pGP->GetPoint() ; ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) { bFound = true ; ptSel = ptP ; m_nLastSnapId = nId ; m_bLastSnapDirOk = false ; } } // se vettore else if ( pGObj->GetType() == GEO_VECT3D) { // recupero il geo-vettore const IGeoVector3d* pGV = GetGeoVector3d( pGObj) ; // recupero il punto Point3d ptP = pGV->GetBase() ; ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) { bFound = true ; ptSel = ptP ; m_nLastSnapId = nId ; m_bLastSnapDirOk = true ; m_vtLastSnapDir = pGV->GetVector() ; m_vtLastSnapDir.ToGlob( frEnt) ; } } // se frame else if ( pGObj->GetType() == GEO_FRAME3D) { // recupero il geo-frame const IGeoFrame3d* pGF = GetGeoFrame3d( pGObj) ; // recupero il punto Point3d ptP = pGF->GetFrame().Orig() ; ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) { bFound = true ; ptSel = ptP ; m_nLastSnapId = nId ; m_bLastSnapDirOk = false ; } } // se curva composita else if ( pGObj->GetType() == CRV_COMPO) { // recupero la curva composita const ICurveComposite* pCrvCompo = GetCurveComposite( pGObj) ; // il punto di riferimento deriva da XY su viewport e Z da selezione Point3d ptWinZ( ptWin.x, ptWin.y, GetSelectedObjWinZ()) ; // determino la curva elementare più vicina al punto di riferimento int nCrv = - 1 ; Point3d ptRef ; if ( UnProject( ptWinZ, ptRef)) { double dPar ; int nFlag ; if ( DistPointCurve( ptRef, *pCrvCompo).GetParamAtMinDistPoint( 0, dPar, nFlag)) nCrv = static_cast( dPar) ; } // ciclo sulle curve elementari int nCont = 0 ; const ICurve* pCrv = pCrvCompo->GetFirstCurve() ; while ( pCrv != nullptr) { // verifico i punti notevoli della curva if ( nCont == nCrv && TestCurveSnapPoints( nSnap, ptWinZ, nId, frEnt, pCrv, dMinSqDist, ptSel)) bFound = true ; // passo alla successiva ++ nCont ; pCrv = pCrvCompo->GetNextCurve() ; } } // se curva semplice 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( ptWin.x, ptWin.y, GetSelectedObjWinZ()) ; // verifico i punti notevoli della curva if ( TestCurveSnapPoints( nSnap, ptWinZ, nId, frEnt, pCrv, dMinSqDist, ptSel)) bFound = true ; } // se testo else if ( pGObj->GetType() == EXT_TEXT) { // recupero il testo const IExtText* pTxt = GetExtText( pGObj) ; // recupero il punto Point3d ptP ; switch ( nSnap) { case SP_END : // punto iniziale if ( pTxt->GetStartPoint( ptP)) { ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) { bFound = true ; ptSel = ptP ; m_nLastSnapId = nId ; m_bLastSnapDirOk = true ; m_vtLastSnapDir = pTxt->GetDirVersor() ; m_vtLastSnapDir.ToGlob( frEnt) ; } } // punto sopra iniziale if ( pTxt->GetOverStartPoint( ptP)) { ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) { bFound = true ; ptSel = ptP ; m_nLastSnapId = nId ; m_bLastSnapDirOk = true ; m_vtLastSnapDir = pTxt->GetDirVersor() ; m_vtLastSnapDir.ToGlob( frEnt) ; } } // punto finale if ( pTxt->GetEndPoint( ptP)) { ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) { bFound = true ; ptSel = ptP ; m_nLastSnapId = nId ; m_bLastSnapDirOk = true ; m_vtLastSnapDir = pTxt->GetDirVersor() ; m_vtLastSnapDir.ToGlob( frEnt) ; } } // punto sopra finale if ( pTxt->GetOverEndPoint( ptP)) { ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) { bFound = true ; ptSel = ptP ; m_nLastSnapId = nId ; m_bLastSnapDirOk = true ; m_vtLastSnapDir = pTxt->GetDirVersor() ; m_vtLastSnapDir.ToGlob( frEnt) ; } } break ; case SP_MID : // punto medio if ( pTxt->GetMidPoint( ptP)) { ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) { bFound = true ; ptSel = ptP ; m_nLastSnapId = nId ; m_bLastSnapDirOk = true ; m_vtLastSnapDir = pTxt->GetDirVersor() ; m_vtLastSnapDir.ToGlob( frEnt) ; } } break ; case SP_CENTER : // centro if ( pTxt->GetCenterPoint( ptP)) { ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) { bFound = true ; ptSel = ptP ; m_nLastSnapId = nId ; m_bLastSnapDirOk = false ; } } break ; } } } return bFound ; } //---------------------------------------------------------------------------- bool Scene::TestCurveSnapPoints( int nSnap, const Point3d& ptWin, int nId, const Frame3d& frEnt, const ICurve* pCrv, double& dMinSqDist, Point3d& ptSel) { // recupero eventuale spessore di estrusione bool bExtr = false ; double dTh ; Vector3d vtExtr ; if ( pCrv->GetExtrusion( vtExtr) && ! vtExtr.IsSmall() && pCrv->GetThickness( dTh) && fabs( dTh) > EPS_SMALL) { vtExtr *= dTh ; vtExtr.ToGlob( frEnt) ; bExtr = true ; } // recupero il punto bool bFound = false ; Point3d ptP ; switch ( nSnap) { case SP_END : // punto iniziale if ( pCrv->GetStartPoint( ptP)) { ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) { bFound = true ; ptSel = ptP ; m_nLastSnapId = nId ; m_bLastSnapDirOk = true ; pCrv->GetStartDir( m_vtLastSnapDir) ; m_vtLastSnapDir.ToGlob( frEnt) ; m_vtLastSnapDir.Invert() ; } // eventuale verifica dell'estruso if ( bExtr) { ptP += vtExtr ; if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) { bFound = true ; ptSel = ptP ; m_nLastSnapId = nId ; m_bLastSnapDirOk = true ; pCrv->GetStartDir( m_vtLastSnapDir) ; m_vtLastSnapDir.ToGlob( frEnt) ; m_vtLastSnapDir.Invert() ; } } } // punto finale if ( pCrv->GetEndPoint( ptP)) { ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) { bFound = true ; ptSel = ptP ; m_nLastSnapId = nId ; m_bLastSnapDirOk = true ; pCrv->GetEndDir( m_vtLastSnapDir) ; m_vtLastSnapDir.ToGlob( frEnt) ; } // eventuale verifica dell'estruso if ( bExtr) { ptP += vtExtr ; if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) { bFound = true ; ptSel = ptP ; m_nLastSnapId = nId ; m_bLastSnapDirOk = true ; pCrv->GetEndDir( m_vtLastSnapDir) ; m_vtLastSnapDir.ToGlob( frEnt) ; } } } break ; case SP_MID : if ( pCrv->GetMidPoint( ptP)) { ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) { bFound = true ; ptSel = ptP ; m_nLastSnapId = nId ; m_bLastSnapDirOk = true ; pCrv->GetMidDir( m_vtLastSnapDir) ; m_vtLastSnapDir.ToGlob( frEnt) ; } // eventuale verifica dell'estruso if ( bExtr) { ptP += vtExtr ; if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) { bFound = true ; ptSel = ptP ; m_nLastSnapId = nId ; m_bLastSnapDirOk = true ; pCrv->GetMidDir( m_vtLastSnapDir) ; m_vtLastSnapDir.ToGlob( frEnt) ; } } } break ; case SP_CENTER : if ( pCrv->GetCenterPoint( ptP)) { ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) { bFound = true ; ptSel = ptP ; m_nLastSnapId = nId ; m_bLastSnapDirOk = false ; } // eventuale verifica dell'estruso if ( bExtr) { ptP += vtExtr ; if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) { bFound = true ; ptSel = ptP ; m_nLastSnapId = nId ; m_bLastSnapDirOk = false ; } } } break ; case SP_NEAR : case SP_TANG : case SP_PERP : case SP_MINDIST : { Point3d ptRef ; // lo porto da spazio grafico a spazio geometrico globale UnProject( ptWin, ptRef) ; // lo porto nel frame della curva ptRef.ToLoc( frEnt) ; // determino il punto più vicino della curva a questo MinDistPCInfo mdInfo ; DistPointCurve dstPtCurve( ptRef, *pCrv) ; if ( dstPtCurve.GetMinDistInfo( 0, mdInfo)) { ptP = mdInfo.ptQ ; ptP.ToGlob( frEnt) ; if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) { bFound = true ; ptSel = ptP ; m_nLastSnapId = nId ; m_bLastSnapDirOk = true ; Point3d ptTmp ; pCrv->GetPointTang( mdInfo.dPar, ICurve::FROM_MINUS, ptTmp, m_vtLastSnapDir) ; m_vtLastSnapDir.ToGlob( frEnt) ; } } // eventuale verifica dell'estruso if ( bExtr) { Vector3d vtTemp = vtExtr ; vtTemp.ToLoc( frEnt) ; // determino il punto più vicino della curva a questo MinDistPCInfo mdInfo ; DistPointCurve dstPtCurve( ptRef - vtTemp, *pCrv) ; if ( dstPtCurve.GetMinDistInfo( 0, mdInfo)) { ptP = mdInfo.ptQ ; ptP.ToGlob( frEnt) ; ptP += vtExtr ; if ( VerifySnapPoint( ptP, ptWin, dMinSqDist)) { bFound = true ; ptSel = ptP ; m_nLastSnapId = nId ; m_bLastSnapDirOk = true ; Point3d ptTmp ; pCrv->GetPointTang( mdInfo.dPar, ICurve::FROM_MINUS, ptTmp, m_vtLastSnapDir) ; m_vtLastSnapDir.ToGlob( frEnt) ; } } } } break ; } return bFound ; } //---------------------------------------------------------------------------- bool Scene::VerifySnapPoint( const Point3d& ptP, const Point3d& ptWin, double& dMinSqDist) { // proietto il punto sulla viewport Point3d ptWinP ; Project( ptP, ptWinP) ; // confronto le distanze double dSqDist = SqDistXY( ptWin, ptWinP) ; if ( dSqDist < dMinSqDist) { dMinSqDist = dSqDist ; return true ; } return false ; } //---------------------------------------------------------------------------- bool Scene::GetSelectedIntersectionPoint( const Point3d& ptWin, int nW, int nH, Point3d& ptSel) { // --- l'intersezione viene calcolata nel piano della griglia --- // verifico siano state selezionate delle entità int nSel ; Select( ptWin, nW, nH, nSel) ; if ( nSel <= 0) return false ; // cerco le prime due curve inquadrate con i loro riferimenti const ICurve* pCrv[2] ; Frame3d frEnt[2] ; double dWinZ = 0 ; int nCrvNum = 0 ; for ( int i = GetFirstSelectedObj() ; i != GDB_ID_NULL && nCrvNum < 2 ; i = GetNextSelectedObj()) { // se non è entità geometrica const IGeoObj* pGObj ; if ( ( pGObj = m_pGeomDB->GetGeoObj( i)) == nullptr) continue ; if ( ( pGObj->GetType() & GEO_CURVE) != 0) { pCrv[nCrvNum] = GetCurve( pGObj) ; if ( ! m_pGeomDB->GetGlobFrame( i, frEnt[nCrvNum])) return false ; dWinZ += 0.5 * GetSelectedObjWinZ() ; ++ nCrvNum ; } } if ( nCrvNum != 2) return false ; // recupero il riferimento di griglia Frame3d frGrid = GetGridFrame() ; // se il riferimento della seconda curva è diverso da quello della griglia, devo trasformarla PtrOwner crvTrans0( nullptr) ; if ( ! AreSameFrame( frEnt[0], frGrid)) { crvTrans0.Set( pCrv[0]->Clone()) ; if ( IsNull( crvTrans0)) return false ; crvTrans0->LocToLoc( frEnt[0], frGrid) ; pCrv[0] = ::Get( crvTrans0) ; } // se il riferimento della seconda curva è diverso da quello della griglia, devo trasformarla PtrOwner crvTrans1( nullptr) ; if ( ! AreSameFrame( frEnt[1], frGrid)) { crvTrans1.Set( pCrv[1]->Clone()) ; if ( IsNull( crvTrans1)) return false ; crvTrans1->LocToLoc( frEnt[1], frGrid) ; pCrv[1] = ::Get( crvTrans1) ; } // uso il punto sketch come punto vicino e lo porto nel riferimento della griglia Point3d ptWinZ( ptWin.x, ptWin.y, dWinZ) ; Point3d ptNear ; if ( ! UnProject( ptWinZ, ptNear)) ptNear = ORIG ; ptNear.ToLoc( frGrid) ; // calcolo il punto di intersezione sulla prima curva più vicino al punto di riferimento IntersCurveCurve intCC( *pCrv[0], *pCrv[1], true) ; if ( ! intCC.GetIntersPointNearTo( 0, ptNear, ptSel)) return false ; ptSel.ToGlob( frGrid) ; return true ; }