Files
EgtGeomKernel/FontNfe.cpp
T
Dario Sassi fcec474a16 EgtGeomKernel :
- in GetOutline dei fonts ora si imposta l'estrusione delle curve
- corretta ArcsBezierCurvesToArcsPerpExtr di CurveComposite per vettore estrusione da prendere dalla composita.
2018-04-16 09:21:41 +00:00

560 lines
18 KiB
C++

//----------------------------------------------------------------------------
// 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 "/EgtDev/Include/EGkGeomDB.h"
#include "/EgtDev/Include/EGkGdbIterator.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)
PtrOwner<IGdbIterator> pIter( CreateGdbIterator( m_pGDB)) ;
if ( IsNull( 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 = max( dHeight, FNT_MIN_HEIGHT) ;
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<IGdbIterator> pIter( CreateGdbIterator( m_pGDB)) ;
if ( IsNull( 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<IGdbIterator> pIter( CreateGdbIterator( m_pGDB)) ;
if ( IsNull( 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) {
// 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 = 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) ;
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)
{
// verifico esistenza font corrente
if ( m_pGDB == nullptr || m_sFont.empty())
return false ;
// creo un iteratore
PtrOwner<IGdbIterator> pIter( CreateGdbIterator( m_pGDB)) ;
if ( IsNull( pIter))
return false ;
// 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 = pIter->GoToFirstInGroup( nGroup) ;
while ( bIter) {
const ICurve* pCrv = GetCurve( pIter->GetGeoObj()) ;
if ( pCrv != nullptr) {
// copia temporanea della curva (trasformando eventuali archi in CurveBezier)
PtrOwner<ICurve> 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 = 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) ;
for ( auto& PL : lstPL)
PL.Translate( vtIpMove) ;
return true ;
}
//----------------------------------------------------------------------------
bool
NfeFont::ApproxWithArcs( const string& sText, int nInsPos, double dLinTol, double dAngTolDeg,
POLYARCLIST& lstPA)
{
// verifico esistenza font corrente
if ( m_pGDB == nullptr || m_sFont.empty())
return false ;
// creo un iteratore
PtrOwner<IGdbIterator> pIter( CreateGdbIterator( m_pGDB)) ;
if ( IsNull( pIter))
return false ;
// 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 = pIter->GoToFirstInGroup( nGroup) ;
while ( bIter) {
const ICurve* pCrv = GetCurve( pIter->GetGeoObj()) ;
if ( pCrv != nullptr) {
// copia temporanea della curva (trasformando eventuali archi in CurveBezier)
PtrOwner<ICurve> 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 = 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) ;
for ( auto& PA : lstPA)
PA.Translate( vtIpMove) ;
return true ;
}
//----------------------------------------------------------------------------
bool
NfeFont::GetTextLines( const string& sText, int nInsPos, PNTVECTOR& vPt, STRVECTOR& vLine)
{
// verifico esistenza font corrente
if ( m_pGDB == nullptr || m_sFont.empty())
return false ;
// creo un iteratore
PtrOwner<IGdbIterator> pIter( CreateGdbIterator( m_pGDB)) ;
if ( IsNull( 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 ;
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.size() > 0) {
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.size() > 0) {
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 ;
}