//---------------------------------------------------------------------------- // EgalTech 2014-2014 //---------------------------------------------------------------------------- // File : FontNfe.cpp Data : 05.06.14 Versione : 1.5f2 // Contenuto : Implementazione della classe NfeFont (formato font proprietario). // // // // Modifiche : 29.05.14 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "FontNfe.h" #include "FontAux.h" #include "/EgtDev/Include/EGkGeomDB.h" #include "/EgtDev/Include/EGkGdbIterator.h" #include "/EgtDev/Include/EGkCurve.h" #include "/EgtDev/Include/EGkCurveAux.h" #include "/EgtDev/Include/EGkExtText.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include "/EgtDev/Include/EgnStringUtils.h" #include "/EgtDev/Include/EGnStringDecoder.h" #include "/EgtDev/Include/EgnFileUtils.h" using namespace std ; //---------------------------------------------------------------------------- const string NFE_H = "H" ; const string NFE_HCAP = "HCAP" ; const string NFE_HX = "HX" ; const string NFE_ASC = "ASC" ; const string NFE_DESC = "DESC" ; const string NFE_ADV = "ADV" ; const string NFE_ITALIC = "ITL" ; const double NFE_ITALIC_STD_SHEAR_COEFF = 0.25 ; const int NFE_MIN_CHAR = 32 ; const int NFE_ERR_CHAR = 127 ; const string NFE_LEN_CHAR = "L" ; //---------------------------------------------------------------------------- NfeFont::NfeFont( void) { m_pGDB = nullptr ; } //---------------------------------------------------------------------------- NfeFont::~NfeFont( void) { if ( m_pGDB != nullptr) delete m_pGDB ; m_pGDB = nullptr ; } //---------------------------------------------------------------------------- bool NfeFont::SetCurrFont( const string& sFont, int nWeight, bool bItalic, double dHeight, double dRatio, double dAddAdvance) { string sFontUp = sFont ; ToUpper( sFontUp) ; // se il font non è già caricato if ( m_pGDB == nullptr || m_sFont != sFontUp) { // pulisco la path del font m_sFont.clear() ; // se necessario creo GDB if ( m_pGDB == nullptr) { m_pGDB = CreateGeomDB() ; if ( m_pGDB == nullptr) return false ; } // pulisco e inizializzo GDB m_pGDB->Init() ; // carico il font if ( ! m_pGDB->Load( sFont)) return false ; // recupero i parametri generali del font (devono essere nel gruppo 1) PtrOwner pIter( CreateGdbIterator( m_pGDB)) ; if ( ! IsValid( pIter)) return false ; if ( ! pIter->GoTo( 1)) return false ; if ( ! pIter->GetInfo( NFE_H, m_dH) || ! pIter->GetInfo( NFE_HCAP, m_dHCap) || ! pIter->GetInfo( NFE_HX, m_dHx) || ! pIter->GetInfo( NFE_ASC, m_dAsc) || ! pIter->GetInfo( NFE_DESC, m_dDesc) || ! pIter->GetInfo( NFE_ADV, m_dAdv)) return false ; if ( m_dH < EPS_SMALL || m_dHCap < EPS_SMALL || m_dHx < EPS_SMALL) return false ; if ( ! pIter->GetInfo( NFE_ITALIC, m_dItalicShearCoeff)) m_dItalicShearCoeff = NFE_ITALIC_STD_SHEAR_COEFF ; // aggiorno la path del font m_sFont = sFontUp ; } // salvo i dati m_nWeight = nWeight ; m_bItalic = bItalic ; m_dHeight = dHeight ; m_dRatio = dRatio ; m_dAddAdvance = dAddAdvance ; return true ; } //---------------------------------------------------------------------------- bool NfeFont::GetCapHeight( double& dCapH) { // verifico esistenza font corrente if ( m_pGDB == nullptr || m_sFont.empty()) return false ; // uso il fattore di scala per Y = m_dHeight / m_dHCap dCapH = m_dHCap * m_dHeight / m_dHCap ; return true ; } //---------------------------------------------------------------------------- bool NfeFont::GetAscent( double& dAsc) { // verifico esistenza font corrente if ( m_pGDB == nullptr || m_sFont.empty()) return false ; // uso il fattore di scala per Y = m_dHeight / m_dHCap dAsc = m_dAsc * m_dHeight / m_dHCap ; return true ; } //---------------------------------------------------------------------------- bool NfeFont::GetDescent( double& dDesc) { // verifico esistenza font corrente if ( m_pGDB == nullptr || m_sFont.empty()) return false ; // uso il fattore di scala per Y = m_dHeight / m_dHCap dDesc = m_dDesc * m_dHeight / m_dHCap ; return true ; } //---------------------------------------------------------------------------- bool NfeFont::GetXBox( const string& sText, int nInsPos, bool bCapOrBound, BBox3d& b3Box) { // verifico esistenza font corrente if ( m_pGDB == nullptr || m_sFont.empty()) return false ; // creo un iteratore PtrOwner pIter( CreateGdbIterator( m_pGDB)) ; if ( ! IsValid( pIter)) return false ; // calcolo i fattori di scala double dScaY = m_dHeight / m_dHCap ; double dScaX = dScaY * m_dRatio ; // recupero altezza maiuscole, ascent, descent e interlinea double dHCap = m_dHeight ; double dAscent = m_dAsc * m_dHeight / m_dHCap ; double dDescent = m_dDesc * m_dHeight / m_dHCap ; double dH = m_dH * m_dHeight / m_dHCap ; // converto i byte della stringa in codici carattere UINTVECTOR vCode ; GetCodePoints( sText, vCode) ; // scandisco i codici double dCurrW = 0 ; double dMaxW = 0 ; double dMinH = 0 ; for ( unsigned int i = 0 ; i < vCode.size() ; ++ i) { // verifico se comando di a capo int nLbLen ; if ( IsLineBreak( vCode, i, nLbLen)) { dCurrW = 0 ; dMinH -= dH ; i += nLbLen ; continue ; } // gruppo del carattere int nGroup = sText[i] ; if ( nGroup < NFE_MIN_CHAR || m_pGDB->GetGdbType( nGroup) != GDB_TY_GROUP) nGroup = NFE_ERR_CHAR ; // recupero lo spostamento per il prossimo carattere double dAdvance ; if ( ! m_pGDB->GetInfo( nGroup, NFE_LEN_CHAR, dAdvance)) dAdvance = m_dAdv ; dCurrW += dAdvance * dScaX + m_dAddAdvance ; if ( dCurrW > dMaxW) dMaxW = dCurrW ; } // punti estremi Point3d ptMin( 0, dMinH - ( bCapOrBound ? 0 : dDescent), 0) ; Point3d ptMax( dMaxW, ( bCapOrBound ? dHCap : dAscent), 0) ; // sistemazioni per la posizione del punto di inserimento Vector3d vtIpMove = GetTextInsertPointMove( dMaxW, dHCap, dMinH, nInsPos) ; ptMin.Translate( vtIpMove) ; ptMax.Translate( vtIpMove) ; // assegno l'ingombro b3Box.Set( ptMin, ptMax) ; return true ; } //---------------------------------------------------------------------------- bool NfeFont::GetOutline( const string& sText, int nInsPos, ICURVEPLIST& lstPC) { // verifico esistenza font corrente if ( m_pGDB == nullptr || m_sFont.empty()) return false ; // creo un iteratore PtrOwner pIter( CreateGdbIterator( m_pGDB)) ; if ( ! IsValid( pIter)) return false ; // calcolo i fattori di scala double dScaY = m_dHeight / m_dHCap ; double dScaX = dScaY * m_dRatio ; double dScaZ = 1 ; // recupero altezza maiuscole e interlinea double dHCap = m_dHeight ; double dH = m_dH * m_dHeight / m_dHCap ; // converto i byte della stringa in codici carattere UINTVECTOR vCode ; GetCodePoints( sText, vCode) ; // scandisco i codici double dMaxW = 0 ; double dMinH = 0 ; Vector3d vtMove ; for ( unsigned int i = 0 ; i < vCode.size() ; ++ i) { // verifico se comando di a capo int nLbLen ; if ( IsLineBreak( vCode, i, nLbLen)) { vtMove.Set( 0, vtMove.y - dH, 0) ; if ( vtMove.y < dMinH) dMinH = vtMove.y ; i += nLbLen ; continue ; } // verifico esistenza del gruppo del carattere int nGroup = vCode[i] ; if ( nGroup < NFE_MIN_CHAR || m_pGDB->GetGdbType( nGroup) != GDB_TY_GROUP) nGroup = NFE_ERR_CHAR ; // ciclo sulle entità geometriche del carattere bool bIter = pIter->GoToFirstInGroup( nGroup) ; while ( bIter) { const ICurve* pCrv = GetCurve( pIter->GetGeoObj()) ; if ( pCrv != nullptr) { ICurve* pCopyCrv = GetCurve( pCrv->Clone()) ; if ( pCopyCrv == nullptr) return false ; lstPC.push_back( pCopyCrv) ; if ( m_bItalic) { // se arco, devo trasformarlo in curva di Bezier (semplice o composta) if ( pCopyCrv->GetType() == CRV_ARC) { ICurve* pCrvNew ; if ( ! ArcToBezierCurve( pCopyCrv, pCrvNew)) return false ; // elimino l'arco e lo sostituisco con la curva di Bezier delete pCopyCrv ; lstPC.back() = pCrvNew ; } pCopyCrv->Shear( ORIG, Y_AX, X_AX, m_dItalicShearCoeff) ; } pCopyCrv->Scale( GLOB_FRM, dScaX, dScaY, dScaZ) ; pCopyCrv->Translate( vtMove) ; } bIter = pIter->GoToNext() ; } // recupero lo spostamento per il prossimo carattere double dAdvance ; if ( ! m_pGDB->GetInfo( nGroup, NFE_LEN_CHAR, dAdvance)) dAdvance = m_dAdv ; vtMove += Vector3d( ( dAdvance * dScaX + m_dAddAdvance), 0, 0) ; if ( vtMove.x > dMaxW) dMaxW = vtMove.x ; } // sistemazioni per la posizione del punto di inserimento Vector3d vtIpMove = GetTextInsertPointMove( dMaxW, dHCap, dMinH, nInsPos) ; ICURVEPLIST::iterator iIter ; for ( iIter = lstPC.begin() ; iIter != lstPC.end() ; ++ iIter) (*iIter)->Translate( vtIpMove) ; return true ; } //---------------------------------------------------------------------------- bool NfeFont::ApproxWithLines( const string& sText, int nInsPos, double dLinTol, double dAngTolDeg, POLYLINELIST& lstPL) { // verifico esistenza font corrente if ( m_pGDB == nullptr || m_sFont.empty()) return false ; // creo un iteratore PtrOwner pIter( CreateGdbIterator( m_pGDB)) ; if ( ! IsValid( pIter)) return false ; // calcolo i fattori di scala double dScaY = m_dHeight / m_dHCap ; double dScaX = dScaY * m_dRatio ; double dScaZ = 1 ; double dInvScaMed = 1 / max( ( dScaX + dScaY) / 2, EPS_SMALL) ; // recupero altezza maiuscole e interlinea double dHCap = m_dHeight ; double dH = m_dH * m_dHeight / m_dHCap ; // converto i byte della stringa in codici carattere UINTVECTOR vCode ; GetCodePoints( sText, vCode) ; // scandisco i codici double dMaxW = 0 ; double dMinH = 0 ; Vector3d vtMove ; for ( unsigned int i = 0 ; i < vCode.size() ; ++ i) { // verifico se comando di a capo int nLbLen ; if ( IsLineBreak( vCode, i, nLbLen)) { vtMove.Set( 0, vtMove.y - dH, 0) ; if ( vtMove.y < dMinH) dMinH = vtMove.y ; i += nLbLen ; continue ; } // verifico esistenza del gruppo del carattere int nGroup = vCode[i] ; if ( nGroup < NFE_MIN_CHAR || m_pGDB->GetGdbType( nGroup) != GDB_TY_GROUP) nGroup = NFE_ERR_CHAR ; // ciclo sulle entità geometriche del carattere bool bIter = pIter->GoToFirstInGroup( nGroup) ; while ( bIter) { const ICurve* pCrv = GetCurve( pIter->GetGeoObj()) ; if ( pCrv != nullptr) { lstPL.push_back( PolyLine()) ; pCrv->ApproxWithLines( dLinTol * dInvScaMed, dAngTolDeg, lstPL.back()) ; if ( m_bItalic) lstPL.back().Shear( ORIG, Y_AX, X_AX, m_dItalicShearCoeff) ; lstPL.back().Scale( GLOB_FRM, dScaX, dScaY, dScaZ) ; lstPL.back().Translate( vtMove) ; } bIter = pIter->GoToNext() ; } // recupero lo spostamento per il prossimo carattere double dAdvance ; if ( ! m_pGDB->GetInfo( nGroup, NFE_LEN_CHAR, dAdvance)) dAdvance = m_dAdv ; vtMove += Vector3d( ( dAdvance * dScaX + m_dAddAdvance), 0, 0) ; if ( vtMove.x > dMaxW) dMaxW = vtMove.x ; } // sistemazioni per la posizione del punto di inserimento Vector3d vtIpMove = GetTextInsertPointMove( dMaxW, dHCap, dMinH, nInsPos) ; POLYLINELIST::iterator iIter ; for ( iIter = lstPL.begin() ; iIter != lstPL.end() ; ++ iIter) (*iIter).Translate( vtIpMove) ; return true ; }