Files
EgtGraphics/SceneGeom.cpp
T
Dario Sassi 6526f7ab9f EgtGraphics 1.6b5 :
- modifiche per gestione superfici trasparenti
- migliorata gestione colore da padre.
2015-02-17 22:45:57 +00:00

600 lines
21 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 "EGrUtils.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 ;
//------------------------------ Local functions -----------------------------
static ObjEGrGraphics* CreateObjEGrGraphics( 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 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::SetSelSurf( Color colSelSurf)
{
m_colSelSurf = colSelSurf ;
return true ;
}
//----------------------------------------------------------------------------
bool
Scene::DrawGroup( int nId, int nPass, const MdStMkCol& 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, const MdStMkCol& 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) ;
// 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 ;
}
//----------------------------------------------------------------------------
bool
Scene::DrawGeoObj( const IGdbIterator& iIter, int nPass, const MdStMkCol& siObj)
{
// valore limite di opacità oltre il quale è considerata completa
const int ALPHA_LIM = 90 ;
// 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)
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()) {
// 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( siObj.colObj) ;
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( siObj.colObj) ;
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( 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( 0.005, 5, PL) ;
pGraphics->Clear() ;
pGraphics->AddColor( siObj.colObj) ;
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) ;
// 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( siObj.colObj) ; // 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 ;
TriFlags3d TFlags ;
TriNormals3d TNrms ;
int nId = pSTM->GetFirstTriangle( Tria) ;
while ( nId != SVT_NULL) {
// se visualizzazione avanzata : edge solo se boundary e normali ai vertici smussate
if ( m_bShowTriaAdvanced) {
pSTM->GetTriangleBoundaryEdges( nId, TFlags) ;
pSTM->GetTriangleSmoothNormals( nId, TNrms) ;
}
// altrimenti : tutti gli edge e normali ai vertici prendono quella del triangolo
else {
for ( int i = 0 ; i < 3 ; ++i) {
TFlags.bFlag[i] = true ;
TNrms.vtN[i] = Tria.GetN() ;
}
}
pGraphics->AddTriangle( Tria, TFlags, 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( siObj.colObj) ;
POLYLINELIST::iterator Iter ;
for ( Iter = lstPL.begin() ; Iter != lstPL.end() ; ++ Iter)
pGraphics->AddPolyLine( *Iter) ;
}
}
// se richiesto, visualizzo la grafica associata
bool bShowAux = false ;
if ( ( nGeoType & GEO_CURVE) != 0 && m_bShowCurveDirection)
bShowAux = true ;
// recupero il valore di opacità (solo per le superfici può esserci trasparenza)
int nAlpha = siObj.colObj.GetIntAlpha() ;
// se hiddenline e non selezione
if ( m_nShowMode == SM_HIDDENLINE && ! m_bSelect) {
// in prima passata disegno solo le superfici opache
if ( nPass == 1 && ( ( nGeoType & GEO_SURF) == 0 || 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 ( ( nGeoType & GEO_SURF) == 0)
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( pGraphics, siObj.nStat, siObj.nMark, nAlpha, bShowAux,
b3Box.GetMin().z, b3Box.GetMax().z) ;
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()) ;
// eseguo visualizzazione
return pGraphics->Draw( siObj.nStat, siObj.nMark, bSurfSha, nAlpha, bShowAux) ;
}
//----------------------------------------------------------------------------
bool
Scene::DrawAlphaSurfVector( void)
{
// ordino vettore in senso crescente secondo Zmin
sort( m_vAlphaSurf.begin(), m_vAlphaSurf.end(),
[]( const AlphaSurf& a, const AlphaSurf&b) { return a.dZmin < b.dZmin ; }) ;
// eseguo visualizzazione
for ( int i = 0 ; i < int( m_vAlphaSurf.size()) ; ++i) {
if ( ! m_vAlphaSurf[i].pGraph->Draw( m_vAlphaSurf[i].nStat, m_vAlphaSurf[i].nMark, true,
m_vAlphaSurf[i].nAlpha, m_vAlphaSurf[i].bShowAux))
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
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 ObjEGrGraphics*
CreateObjEGrGraphics( bool bNewWay)
{
if ( bNewWay)
return ( new ObjNewGraphics) ;
else
return ( new 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 = ORIG + Vector3d( 0, 0.5 * dLenTr, 0) ;
ptP0.ToGlob( frF) ;
plMark.AddUPoint( 0, ptP0) ;
Point3d ptP1 = ORIG + Vector3d( 0, - 0.5 * dLenTr, 0) ;
ptP1.ToGlob( frF) ;
plMark.AddUPoint( 1, ptP1) ;
}
else {
frF.Set( ptTail, vtDir) ;
Point3d ptP0 = ORIG + Vector3d( - 0.5 * dLenTr, - 0.5 * dLenTr, 0) ;
ptP0.ToGlob( frF) ;
plMark.AddUPoint( 0, ptP0) ;
Point3d ptP1 = ORIG + Vector3d( 0.5 * dLenTr, - 0.5 * dLenTr, 0) ;
ptP1.ToGlob( frF) ;
plMark.AddUPoint( 1, ptP1) ;
Point3d ptP2 = ORIG + Vector3d( 0.5 * dLenTr, 0.5 * dLenTr, 0) ;
ptP2.ToGlob( frF) ;
plMark.AddUPoint( 2, ptP2) ;
Point3d ptP3 = ORIG + Vector3d( - 0.5 * dLenTr, 0.5 * dLenTr, 0) ;
ptP3.ToGlob( 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 = ORIG + Vector3d( 0, A_WIDTH_COEFF, -1) * dLenArr ;
ptP1.ToGlob( frF) ;
plArr.AddUPoint( 1, ptP1) ;
Point3d ptP2 = ORIG + Vector3d( 0, - A_WIDTH_COEFF, -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 ;
}