e1e4af8792
- aggiunta gestione entità da non selezionare (Unselectable).
486 lines
17 KiB
C++
486 lines
17 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2013-2014
|
|
//----------------------------------------------------------------------------
|
|
// File : SceneGeom.cpp Data : 10.02.14 Versione : 1.5b1
|
|
// 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 "/EgtDev/Include/EgtILogger.h"
|
|
#include "/EgtDev/Include/EGnStringUtils.h"
|
|
#include "/EgtDev/Include/EGkFrame3d.h"
|
|
#include "/EgtDev/Include/EgtPointerOwner.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/EGkExtText.h"
|
|
#include "/EgtDev/Include/EGkGdbFunct.h"
|
|
|
|
using namespace std ;
|
|
|
|
//------------------------------ Constants -----------------------------------
|
|
const int OGLMAT_DIM = 16 ;
|
|
|
|
//------------------------------ Local functions -----------------------------
|
|
static bool FrameToOpenGlMatrix( const Frame3d& frFrame, double Matrix[OGLMAT_DIM]) ;
|
|
static ObjEGrGraphics* CreateObjEGrGraphics( bool bNewWay) ;
|
|
static bool CalcCurveTipArrow( const PolyLine& plCrv, PolyLine& plArr) ;
|
|
static bool CalcConnectingLines( const PolyLine& plCrv, const Vector3d& vtTh, bool bDense, 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::DrawGroup( int nId, int nPass, MdStMk cParent)
|
|
{
|
|
// creo un iteratore
|
|
PtrOwner<IGdbIterator> 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, MdStMk cParent)
|
|
{
|
|
// creo un iteratore
|
|
PtrOwner<IGdbIterator> 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 && bOk ;
|
|
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) ;
|
|
// 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, MdStMk( nMode, nStat, nMark)))
|
|
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, MdStMk( nMode, nStat, nMark)))
|
|
bOk = false ;
|
|
}
|
|
}
|
|
}
|
|
// se necessario, ripristino lo stack delle matrici
|
|
if ( bMatrix)
|
|
glPopMatrix() ;
|
|
|
|
return bOk ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::DrawGeoObj( const IGdbIterator& iIter, int nPass, MdStMk siObj)
|
|
{
|
|
// recupero l'oggetto geometrico e il suo tipo
|
|
IGeoObj* pGeoObj = (const_cast<IGdbIterator*>(&iIter))->GetGeoObj() ;
|
|
if ( pGeoObj == nullptr)
|
|
return false ;
|
|
int nGeoType = pGeoObj->GetType() ;
|
|
|
|
// se non esiste grafica associata, la creo
|
|
if ( pGeoObj->GetObjGraphics() == nullptr) {
|
|
// nuova modalità grafica solo per superfici con molti triangoli
|
|
const int N_MIN_TRIA_NEWWAY = 100 ;
|
|
bool bNewWay = false ;
|
|
if ( m_bNewWay && nGeoType == SRF_TRIMESH) {
|
|
const ISurfTriMesh* pSTM = GetSurfTriMesh( pGeoObj) ;
|
|
if ( pSTM != nullptr && pSTM->GetTriangleNum() > N_MIN_TRIA_NEWWAY)
|
|
m_bNewWay = true ;
|
|
}
|
|
ObjEGrGraphics* pGraphics = CreateObjEGrGraphics( 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()) {
|
|
// recupero il colore
|
|
Color cCol ;
|
|
if ( ! iIter.GetCalcMaterial( cCol))
|
|
cCol = m_colDef ;
|
|
// se vettore
|
|
if ( nGeoType == GEO_VECT3D) {
|
|
// recupero il vettore
|
|
const IGeoVector3d* pVector = GetGeoVector3d( pGeoObj) ;
|
|
if ( pVector == nullptr)
|
|
return false ;
|
|
// calcolo la grafica
|
|
PolyLine PL ;
|
|
pVector->GetDrawWithArrowHead( 0.1, 10, PL) ;
|
|
pGraphics->Clear() ;
|
|
pGraphics->AddColor( cCol) ;
|
|
pGraphics->AddPolyLine( PL) ;
|
|
}
|
|
// 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( cCol) ;
|
|
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( 10, 0.1, plX, plY, plZ) ;
|
|
pGraphics->Clear() ;
|
|
pGraphics->AddColor( RED) ;
|
|
pGraphics->AddPolyLine( plX) ;
|
|
pGraphics->AddColor( GREEN) ;
|
|
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( 0.005, 5, PL) ;
|
|
pGraphics->Clear() ;
|
|
pGraphics->AddColor( cCol) ;
|
|
pGraphics->AddPolyLine( PL) ;
|
|
// eventuali segni ausiliari (frecce,...)
|
|
//Point3d ptStart ;
|
|
//if ( PL.GetFirstPoint( ptStart))
|
|
// pGraphics->AddPoint( ptStart, true) ;
|
|
PolyLine PLA ;
|
|
if ( CalcCurveTipArrow( PL, PLA))
|
|
pGraphics->AddPolyLine( PLA, true) ;
|
|
// eventuale spessore
|
|
double dTh ;
|
|
Vector3d vtExtr ;
|
|
if ( pCurve->GetExtrusion( vtExtr) && ! vtExtr.IsSmall() &&
|
|
pCurve->GetThickness( dTh) && fabs( dTh) > EPS_SMALL) {
|
|
// segmenti di raccordo
|
|
PNTVECTOR vPnt ;
|
|
bool bDense = ( nGeoType == CRV_ARC || nGeoType == CRV_BEZ) ;
|
|
if ( CalcConnectingLines( PL, dTh * vtExtr, bDense, vPnt))
|
|
pGraphics->AddLines( vPnt) ;
|
|
// percorso traslato
|
|
PL.Translate( dTh * vtExtr) ;
|
|
pGraphics->AddPolyLine( PL) ;
|
|
}
|
|
}
|
|
// se superficie trimesh
|
|
else if ( nGeoType == SRF_TRIMESH) {
|
|
// recupero la superficie
|
|
const ISurfTriMesh* pSTM = GetSurfTriMesh( pGeoObj) ;
|
|
if ( pSTM == nullptr)
|
|
return false ;
|
|
// recupero il materiale
|
|
Material mMat ;
|
|
if ( ! iIter.GetCalcMaterial( mMat))
|
|
mMat.Set( m_colDef) ;
|
|
// impostazioni iniziali
|
|
pGraphics->Clear() ;
|
|
pGraphics->AddColor( cCol) ; // per wireframe
|
|
pGraphics->AddMaterial( mMat.GetAmbient(), mMat.GetDiffuse(),
|
|
mMat.GetSpecular(), mMat.GetShininess()) ;
|
|
pGraphics->AddBackMaterial( GetSurfBackColor( mMat.GetDiffuse())) ;
|
|
pGraphics->StartTriangles( pSTM->GetTriangleNum()) ;
|
|
// ciclo sui triangoli della superficie
|
|
Triangle3d Tria ;
|
|
TriNormals3d TNrms ;
|
|
int nId = pSTM->GetFirstTriangle( Tria) ;
|
|
while ( nId != SVT_NULL) {
|
|
pSTM->GetTriangleSmoothNormals( nId, TNrms) ;
|
|
pGraphics->AddTriangle( Tria, TNrms) ;
|
|
nId = pSTM->GetNextTriangle( nId, Tria) ;
|
|
}
|
|
pGraphics->EndTriangles() ;
|
|
}
|
|
// se testo
|
|
else if ( nGeoType == EXT_TEXT) {
|
|
// recupero il testo
|
|
const IExtText* pTXT = GetExtText( pGeoObj) ;
|
|
if ( pTXT == nullptr)
|
|
return false ;
|
|
// calcolo la grafica
|
|
POLYLINELIST lstPL ;
|
|
pTXT->ApproxWithLines( 0.01, 5, lstPL) ;
|
|
pGraphics->Clear() ;
|
|
pGraphics->AddColor( cCol) ;
|
|
POLYLINELIST::iterator Iter ;
|
|
for ( Iter = lstPL.begin() ; Iter != lstPL.end() ; ++ Iter)
|
|
pGraphics->AddPolyLine( *Iter) ;
|
|
}
|
|
}
|
|
|
|
// se hiddenline e non selezione
|
|
if ( m_nShowMode == SM_HIDDENLINE && ! m_bSelect) {
|
|
// in prima passata disegno solo le superfici
|
|
if ( nPass == 1 && ( nGeoType & GEO_SURF) == 0)
|
|
return true ;
|
|
}
|
|
|
|
// se shading e non selezione
|
|
if ( m_nShowMode == SM_SHADING && ! m_bSelect) {
|
|
// in prima passata disegno solo le superfici
|
|
if ( nPass == 1 && ( nGeoType & GEO_SURF) == 0)
|
|
return true ;
|
|
// in seconda passata disegno solo dimensioni 0 e curve
|
|
if ( nPass == 2 && ( nGeoType & GEO_SURF) != 0)
|
|
return true ;
|
|
}
|
|
|
|
// se in selezione, carico il nome
|
|
if ( m_bSelect)
|
|
glLoadName( iIter.GetId()) ;
|
|
|
|
// se richiesto, visualizzo la grafica associata
|
|
bool bShowAux = false ;
|
|
if ( ( nGeoType & GEO_CURVE) != 0 && m_bShowCurveDirection)
|
|
bShowAux = true ;
|
|
return pGraphics->Draw( siObj.nStat, siObj.nMark, bShowAux) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::DeleteObjGraphicsGroup( int nId)
|
|
{
|
|
// creo un iteratore
|
|
PtrOwner<IGdbIterator> 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 bool
|
|
FrameToOpenGlMatrix( const Frame3d& frFrame, double Matrix[OGLMAT_DIM])
|
|
{
|
|
if ( frFrame.GetType() == Frame3d::ERR)
|
|
return false ;
|
|
|
|
Matrix[0] = frFrame.VersX().x ;
|
|
Matrix[1] = frFrame.VersX().y ;
|
|
Matrix[2] = frFrame.VersX().z ;
|
|
Matrix[3] = 0 ;
|
|
Matrix[4] = frFrame.VersY().x ;
|
|
Matrix[5] = frFrame.VersY().y ;
|
|
Matrix[6] = frFrame.VersY().z ;
|
|
Matrix[7] = 0 ;
|
|
Matrix[8] = frFrame.VersZ().x ;
|
|
Matrix[9] = frFrame.VersZ().y ;
|
|
Matrix[10] = frFrame.VersZ().z ;
|
|
Matrix[11] = 0 ;
|
|
Matrix[12] = frFrame.Orig().x ;
|
|
Matrix[13] = frFrame.Orig().y ;
|
|
Matrix[14] = frFrame.Orig().z ;
|
|
Matrix[15] = 1 ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static ObjEGrGraphics*
|
|
CreateObjEGrGraphics( bool bNewWay)
|
|
{
|
|
if ( bNewWay)
|
|
return ( new ObjNewGraphics) ;
|
|
else
|
|
return ( new ObjOldGraphics) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
CalcCurveTipArrow( 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 = 3 ;
|
|
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)) {
|
|
vtDir = ptTip - ptP1 ;
|
|
dLen = vtDir.Len() ;
|
|
vtDir /= dLen ;
|
|
}
|
|
else
|
|
break ;
|
|
}
|
|
// recupero lunghezza del percorso
|
|
double dLenRef = 0 ;
|
|
plCrv.GetApproxLength( dLenRef) ;
|
|
// lunghezza della freccia
|
|
const double LEN_COEFF = 0.25 ;
|
|
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 ;
|
|
frF.Set( ptTip, vtDir) ;
|
|
plArr.AddUPoint( 0, ptTip) ;
|
|
Point3d ptP1 = ORIG + Vector3d( A_WIDTH_COEFF, 0, -1) * dLenArr ;
|
|
ptP1.ToGlob( frF) ;
|
|
plArr.AddUPoint( 1, ptP1) ;
|
|
Point3d ptP2 = ORIG + Vector3d( -A_WIDTH_COEFF, 0, -1) * dLenArr ;
|
|
ptP2.ToGlob( frF) ;
|
|
plArr.AddUPoint( 2, ptP2) ;
|
|
plArr.AddUPoint( 3, ptTip) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
CalcConnectingLines( const PolyLine& plCrv, const Vector3d& vtTh, bool bDense, PNTVECTOR& vPnt)
|
|
{
|
|
// assegno coefficiente
|
|
double dDelta = ( bDense ? 0.25 : 1) ;
|
|
// 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) {
|
|
Point3d ptP ;
|
|
plCrv.GetCurrPoint( ptP) ;
|
|
vPnt.push_back( ptP) ;
|
|
ptP += vtTh ;
|
|
vPnt.push_back( ptP) ;
|
|
dUprev += dDelta ;
|
|
}
|
|
}
|
|
return true ;
|
|
} |