//---------------------------------------------------------------------------- // 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 "FontConst.h" #include "GdbIterator.h" #include "/EgtDev/Include/EGkGeomDB.h" #include "/EgtDev/Include/EGkCurve.h" #include "/EgtDev/Include/EGkCurveAux.h" #include "/EgtDev/Include/EGkCurveComposite.h" #include "/EgtDev/Include/EGkExtText.h" #include "/EgtDev/Include/EGnStringUtils.h" #include "/EgtDev/Include/EGnFileUtils.h" #include "/EgtDev/Include/EgtStringDecoder.h" #include "/EgtDev/Include/EgtStringEncoder.h" #include "/EgtDev/Include/EgtPointerOwner.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) GdbIterator iIter( m_pGDB) ; if ( ! iIter.GoTo( 1)) return false ; if ( ! iIter.GetInfo( NFE_H, m_dH) || ! iIter.GetInfo( NFE_HCAP, m_dHCap) || ! iIter.GetInfo( NFE_HX, m_dHx) || ! iIter.GetInfo( NFE_ASC, m_dAsc) || ! iIter.GetInfo( NFE_DESC, m_dDesc) || ! iIter.GetInfo( NFE_ADV, m_dAdv)) return false ; if ( m_dH < EPS_SMALL || m_dHCap < EPS_SMALL || m_dHx < EPS_SMALL) return false ; if ( ! iIter.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 = max( dHeight, FNT_MIN_HEIGHT) ; m_dRatio = dRatio ; m_dAddAdvance = dAddAdvance ; return true ; } //---------------------------------------------------------------------------- bool NfeFont::GetCapHeight( double& dCapH) const { // 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) const { // 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) const { // 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) const { // verifico esistenza font corrente if ( m_pGDB == nullptr || m_sFont.empty()) 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) const { // verifico esistenza font corrente if ( m_pGDB == nullptr || m_sFont.empty()) return false ; // creo un iteratore GdbIterator iIter( m_pGDB) ; // 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 = iIter.GoToFirstInGroup( nGroup) ; while ( bIter) { const ICurve* pCrv = GetCurve( iIter.GetGeoObj()) ; if ( pCrv != nullptr) { // copio la curva (trasformando eventuali archi in CurveBezier) ICurve* pCrvNew = CurveToNoArcsCurve( pCrv) ; if ( pCrvNew == nullptr) return false ; // eseguo trasformazioni if ( m_bItalic) pCrvNew->Shear( ORIG, Y_AX, X_AX, m_dItalicShearCoeff) ; pCrvNew->Scale( GLOB_FRM, dScaX, dScaY, dScaZ) ; pCrvNew->Translate( vtMove) ; // inserisco in lista la nuova curva lstPC.push_back( pCrvNew) ; } bIter = iIter.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) ; for ( const auto& pCrv : lstPC) pCrv->Translate( vtIpMove) ; // assegno l'estrusione for ( const auto& pCrv : lstPC) pCrv->SetExtrusion( Z_AX) ; return true ; } //---------------------------------------------------------------------------- bool NfeFont::ApproxWithLines( const string& sText, int nInsPos, double dLinTol, double dAngTolDeg, POLYLINELIST& lstPL) const { // verifico esistenza font corrente if ( m_pGDB == nullptr || m_sFont.empty()) return false ; // creo un iteratore GdbIterator iIter( m_pGDB) ; // controllo valore tolleranza lineare if ( dLinTol > FNT_MAX_LINTOL_TO_H * m_dHeight) dLinTol = max( FNT_MAX_LINTOL_TO_H * m_dHeight, EPS_SMALL) ; // 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 = iIter.GoToFirstInGroup( nGroup) ; while ( bIter) { const ICurve* pCrv = GetCurve( iIter.GetGeoObj()) ; if ( pCrv != nullptr) { // copia temporanea della curva (trasformando eventuali archi in CurveBezier) PtrOwner pCrvNew( CurveToNoArcsCurve( pCrv)) ; if ( IsNull( pCrvNew)) return false ; // eseguo trasformazioni if ( m_bItalic) pCrvNew->Shear( ORIG, Y_AX, X_AX, m_dItalicShearCoeff) ; pCrvNew->Scale( GLOB_FRM, dScaX, dScaY, dScaZ) ; pCrvNew->Translate( vtMove) ; // approssimo con linee lstPL.emplace_back() ; pCrvNew->ApproxWithLines( dLinTol, dAngTolDeg, ICurve::APL_STD, lstPL.back()) ; } bIter = iIter.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) ; for ( auto& PL : lstPL) PL.Translate( vtIpMove) ; return true ; } //---------------------------------------------------------------------------- bool NfeFont::ApproxWithArcs( const string& sText, int nInsPos, double dLinTol, double dAngTolDeg, POLYARCLIST& lstPA) const { // verifico esistenza font corrente if ( m_pGDB == nullptr || m_sFont.empty()) return false ; // creo un iteratore GdbIterator iIter( m_pGDB) ; // controllo valore tolleranza lineare if ( dLinTol > FNT_MAX_LINTOL_TO_H * m_dHeight) dLinTol = max( FNT_MAX_LINTOL_TO_H * m_dHeight, EPS_SMALL) ; // 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 = iIter.GoToFirstInGroup( nGroup) ; while ( bIter) { const ICurve* pCrv = GetCurve( iIter.GetGeoObj()) ; if ( pCrv != nullptr) { // copia temporanea della curva (trasformando eventuali archi in CurveBezier) PtrOwner pCrvNew( CurveToNoArcsCurve( pCrv)) ; if ( IsNull( pCrvNew)) return false ; // eseguo trasformazioni if ( m_bItalic) pCrvNew->Shear( ORIG, Y_AX, X_AX, m_dItalicShearCoeff) ; pCrvNew->Scale( GLOB_FRM, dScaX, dScaY, dScaZ) ; pCrvNew->Translate( vtMove) ; // approssimo con archi lstPA.emplace_back() ; pCrv->ApproxWithArcs( dLinTol, dAngTolDeg, lstPA.back()) ; } bIter = iIter.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) ; for ( auto& PA : lstPA) PA.Translate( vtIpMove) ; return true ; } //---------------------------------------------------------------------------- bool NfeFont::GetTextLines( const string& sText, int nInsPos, PNTVECTOR& vPt, STRVECTOR& vLine) const { // verifico esistenza font corrente if ( m_pGDB == nullptr || m_sFont.empty()) return false ; // calcolo i fattori di scala double dScaY = m_dHeight / m_dHCap ; double dScaX = dScaY * m_dRatio ; // 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 ; UINTVECTOR vTmpCode ; for ( unsigned int i = 0 ; i < vCode.size() ; ++ i) { // verifico se comando di a capo int nLbLen ; if ( IsLineBreak( vCode, i, nLbLen)) { // salvo la linea, se contiene qualcosa if ( ! vTmpCode.empty()) { string sLine ; SetCodePoints( vTmpCode, sLine) ; vLine.push_back( sLine) ; vTmpCode.clear() ; vPt.emplace_back( 0, vtMove.y, 0) ; } // sistemo la posizione vtMove.Set( 0, vtMove.y - dH, 0) ; if ( vtMove.y < dMinH) dMinH = vtMove.y ; // passo oltre i += nLbLen ; continue ; } // salvo il codice vTmpCode.push_back( vCode[i]) ; // 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 ; // 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 ; } // salvo eventuale ultima linea if ( ! vTmpCode.empty()) { string sLine ; SetCodePoints( vTmpCode, sLine) ; vLine.push_back( sLine) ; vTmpCode.clear() ; vPt.emplace_back( 0, vtMove.y, 0) ; } // sistemazioni per la posizione del punto di inserimento Vector3d vtIpMove = GetTextInsertPointMove( dMaxW, dHCap, dMinH, nInsPos) ; for ( auto& Pt : vPt) Pt.Translate( vtIpMove) ; return true ; }