//---------------------------------------------------------------------------- // EgalTech 2014-2014 //---------------------------------------------------------------------------- // File : FontOs.cpp Data : 05.06.14 Versione : 1.5f2 // Contenuto : Implementazione della classe OsFont (font di sistema). // // // // Modifiche : 01.06.14 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "FontOs.h" #include "FontAux.h" #include "FontConst.h" #include "CurveLine.h" #include "CurveBezier.h" #include "CurveComposite.h" #include "SurfFlatRegion.h" #include "GeoConst.h" #include "/EgtDev/Include/EGkGeomDB.h" #include "/EgtDev/Include/EGkGdbIterator.h" #include "/EgtDev/Include/EGkCurve.h" #include "/EgtDev/Include/EGkCurveAux.h" #include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EGnStringUtils.h" #include "/EgtDev/Include/EGnFileUtils.h" #include "/EgtDev/Include/EgtStringConverter.h" #include "/EgtDev/Include/EgtStringDecoder.h" #include "/EgtDev/Include/EgtStringEncoder.h" #include "/EgtDev/Include/EgtPointerOwner.h" using namespace std ; //---------------------------------------------------------------------------- const int OSF_HSTD = 100 ; //---------------------------------------------------------------------------- OsFont::OsFont( void) { m_hDC = nullptr ; m_hFont = nullptr ; } //---------------------------------------------------------------------------- OsFont::~OsFont( void) { if ( m_hFont != nullptr) DeleteObject( m_hFont) ; m_hFont = nullptr ; if ( m_hDC != nullptr) ReleaseDC( NULL, m_hDC) ; m_hDC = nullptr ; } //---------------------------------------------------------------------------- bool OsFont::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 o sono cambiati dei parametri di creazione if ( m_sFont != sFontUp || nWeight != m_nWeight || bItalic != m_bItalic) { // pulisco la path del font m_sFont.clear() ; // cancello eventuale precedente font if ( m_hFont != nullptr) DeleteObject( m_hFont) ; // se necessario, recupero il device di schermo if ( m_hDC == nullptr) m_hDC = GetDC( nullptr) ; if ( m_hDC == nullptr) return false ; ::SetMapMode( m_hDC, MM_TEXT) ; // creo il font m_hFont = CreateFontW( - OSF_HSTD, 0, 0, 0, nWeight, bItalic, false, false, DEFAULT_CHARSET, OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH, stringtoW( sFont)) ; if ( m_hFont == nullptr) return false ; // aggiorno dati del font if ( ! CalcFontData()) return false ; // 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 OsFont::CalcFontData( void) { // verifico esistenza font corrente (non controllo nome) if ( m_hDC == nullptr || m_hFont == nullptr) return false ; // rendo corrente il font HFONT hPrevFont = (HFONT) SelectObject( m_hDC, m_hFont) ; if ( hPrevFont == nullptr) return false ; // dati generali TEXTMETRIC tm ; if ( ! GetTextMetrics( m_hDC, &tm)) return false ; double dCoeff = (( tm.tmHeight > 0) ? double( OSF_HSTD) / tm.tmHeight : 1) ; m_dH = ( tm.tmHeight + tm.tmExternalLeading) * dCoeff ; m_dHCap = ( tm.tmAscent - tm.tmInternalLeading) * dCoeff ; m_dHx = 0.6667 * m_dHCap ; // approx m_dAsc = tm.tmAscent * dCoeff ; m_dDesc = tm.tmDescent * dCoeff ; m_dAdv = tm.tmMaxCharWidth * dCoeff ; // cerco dato più preciso su altezza delle maiuscole GLYPHMETRICS gm ; MAT2 mat = { {0,1},{0,0},{0,0},{0,1}} ; // recupero l'altezza della lettera 'H' (72) DWORD dwSize = GetGlyphOutlineW( m_hDC, 72, GGO_NATIVE, &gm, 0, NULL, &mat) ; if ( dwSize != GDI_ERROR) { m_dHCap = gm.gmBlackBoxY ; m_dHx = 0.6667 * m_dHCap ; // approx } // ripristino il font originale SelectObject( m_hDC, hPrevFont) ; return true ; } //---------------------------------------------------------------------------- bool OsFont::GetCapHeight( double& dCapH) const { // verifico esistenza font corrente if ( m_hDC == nullptr || m_hFont == 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 OsFont::GetAscent( double& dAsc) const { // verifico esistenza font corrente if ( m_hDC == nullptr || m_hFont == 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 OsFont::GetDescent( double& dDesc) const { // verifico esistenza font corrente if ( m_hDC == nullptr || m_hFont == 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 OsFont::GetXBox( const string& sText, int nInsPos, bool bCapOrBound, BBox3d& b3Box) const { // verifico esistenza font corrente if ( m_hDC == nullptr || m_hFont == nullptr || m_sFont.empty()) return false ; // rendo corrente il font HFONT hPrevFont = (HFONT) SelectObject( m_hDC, m_hFont) ; if ( hPrevFont == nullptr) 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 ; } // recupero l'avanzamento di ogni carattere ABC abc ; double dAdvance ; if ( GetCharABCWidths( m_hDC, vCode[i], vCode[i], &abc)) dAdvance = ( abc.abcA + abc.abcB + abc.abcC) ; else 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) ; // ripristino il font originale SelectObject( m_hDC, hPrevFont) ; return true ; } //---------------------------------------------------------------------------- bool OsFont::GetOutline( const string& sText, int nInsPos, ICURVEPLIST& lstPC) const { // verifico esistenza font corrente if ( m_hDC == nullptr || m_hFont == nullptr || m_sFont.empty()) return false ; // rendo corrente il font HFONT hPrevFont = (HFONT) SelectObject( m_hDC, m_hFont) ; if ( hPrevFont == nullptr) 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) ; // ciclo sui codici double dMaxW = 0 ; double dMinH = 0 ; Vector3d vtMove ; ICURVEPLIST lstTmpPC ; 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 ; } // recupero l'outline double dAdvance ; if ( ! GetCharOutline( vCode[i], dAdvance, lstTmpPC)) return false ; // lo trasformo opportunamente for ( auto iIter = lstTmpPC.begin() ; iIter != lstTmpPC.end() ; ++ iIter) { // trasformazioni (*iIter)->Scale( GLOB_FRM, dScaX, dScaY, dScaZ) ; (*iIter)->Translate( vtMove) ; // inserimento nella lista principale lstPC.push_back( (*iIter)) ; } vtMove += Vector3d( dAdvance * dScaX + m_dAddAdvance, 0, 0) ; if ( vtMove.x > dMaxW) dMaxW = vtMove.x ; // ciclo di pulizia ( non devo cancellare le curve, perchè spostate nella lista principale) lstTmpPC.clear() ; } // sistemazioni per la posizione del punto di inserimento Vector3d vtIpMove = GetTextInsertPointMove( dMaxW, dHCap, dMinH, nInsPos) ; for ( const auto& pCrv : lstPC) pCrv->Translate( vtIpMove) ; // inverto i percorsi per avere gli esterni CCW for ( const auto& pCrv : lstPC) pCrv->Invert() ; // assegno l'estrusione for ( const auto& pCrv : lstPC) pCrv->SetExtrusion( Z_AX) ; // ripristino il font originale SelectObject( m_hDC, hPrevFont) ; return true ; } //---------------------------------------------------------------------------- bool OsFont::GetRegion( const string& sText, int nInsPos, ISURFFRPLIST& lstSFR) const { // verifico esistenza font corrente if ( m_hDC == nullptr || m_hFont == nullptr || m_sFont.empty()) return false ; // rendo corrente il font HFONT hPrevFont = (HFONT) SelectObject( m_hDC, m_hFont) ; if ( hPrevFont == nullptr) 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) ; // ciclo sui 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 ; } // recupero l'outline double dAdvance ; ICURVEPLIST lstPC ; if ( ! GetCharOutline( vCode[i], dAdvance, lstPC)) return false ; // lo trasformo opportunamente for ( auto iIter = lstPC.begin() ; iIter != lstPC.end() ; ++ iIter) { // inverto i percorsi per avere gli esterni CCW (*iIter)->Invert() ; // la trasformo per avere solo archi e rette GetCurveComposite( *iIter)->ArcsBezierCurvesToArcsPerpExtr( LIN_TOL_FINE, ANG_STRAIGHT) ; } // creo la regione SurfFlatRegionByContours SfrCntr( false, true) ; for ( auto& PC : lstPC) SfrCntr.AddCurve( PC) ; PtrOwner pSfr( GetBasicSurfFlatRegion( SfrCntr.GetSurf())) ; if ( ! IsNull( pSfr)) { // trasformazioni pSfr->Scale( GLOB_FRM, dScaX, dScaY, dScaZ) ; pSfr->Translate( vtMove) ; // inserimento in lista lstSFR.push_back( Release( pSfr)) ; } // aggiorno per larghezza 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& pSfr : lstSFR) pSfr->Translate( vtIpMove) ; // ripristino il font originale SelectObject( m_hDC, hPrevFont) ; return true ; } //---------------------------------------------------------------------------- bool OsFont::ApproxWithLines( const string& sText, int nInsPos, double dLinTol, double dAngTolDeg, POLYLINELIST& lstPL) const { // verifico esistenza font corrente if ( m_hDC == nullptr || m_hFont == nullptr || m_sFont.empty()) return false ; // rendo corrente il font HFONT hPrevFont = (HFONT) SelectObject( m_hDC, m_hFont) ; if ( hPrevFont == nullptr) 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) ; // ciclo sui caratteri double dMaxW = 0 ; double dMinH = 0 ; Vector3d vtMove ; ICURVEPLIST lstPC ; 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 ; } // recupero l'outline double dAdvance ; if ( ! GetCharOutline( vCode[i], dAdvance, lstPC)) return false ; // lo approssimo con segmenti di retta for ( auto iIter = lstPC.begin() ; iIter != lstPC.end() ; ++ iIter) { // trasformazioni (*iIter)->Scale( GLOB_FRM, dScaX, dScaY, dScaZ) ; (*iIter)->Translate( vtMove) ; // approssimo con rette lstPL.emplace_back() ; if ( ! (*iIter)->ApproxWithLines( dLinTol, dAngTolDeg, ICurve::APL_STD, lstPL.back())) return false ; } vtMove += Vector3d( dAdvance * dScaX + m_dAddAdvance, 0, 0) ; if ( vtMove.x > dMaxW) dMaxW = vtMove.x ; // ciclo di pulizia for ( auto iIter = lstPC.begin() ; iIter != lstPC.end() ; ++ iIter) delete (*iIter) ; lstPC.clear() ; } // sistemazioni per la posizione del punto di inserimento Vector3d vtIpMove = GetTextInsertPointMove( dMaxW, dHCap, dMinH, nInsPos) ; for ( auto& PL : lstPL) PL.Translate( vtIpMove) ; // inverto le polilinee per avere gli esterni CCW for ( auto& PL : lstPL) PL.Invert() ; // ripristino il font originale SelectObject( m_hDC, hPrevFont) ; return true ; } //---------------------------------------------------------------------------- bool OsFont::ApproxWithArcs( const string& sText, int nInsPos, double dLinTol, double dAngTolDeg, POLYARCLIST& lstPA) const { // verifico esistenza font corrente if ( m_hDC == nullptr || m_hFont == nullptr || m_sFont.empty()) return false ; // rendo corrente il font HFONT hPrevFont = (HFONT) SelectObject( m_hDC, m_hFont) ; if ( hPrevFont == nullptr) 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) ; // ciclo sui caratteri double dMaxW = 0 ; double dMinH = 0 ; Vector3d vtMove ; ICURVEPLIST lstPC ; 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 ; } // recupero l'outline double dAdvance ; if ( ! GetCharOutline( vCode[i], dAdvance, lstPC)) return false ; // lo approssimo con segmenti di arco e retta for ( auto iIter = lstPC.begin() ; iIter != lstPC.end() ; ++ iIter) { // trasformazioni (*iIter)->Scale( GLOB_FRM, dScaX, dScaY, dScaZ) ; (*iIter)->Translate( vtMove) ; // approssimo con archi lstPA.emplace_back() ; if ( ! (*iIter)->ApproxWithArcs( dLinTol, dAngTolDeg, lstPA.back())) return false ; } vtMove += Vector3d( dAdvance * dScaX + m_dAddAdvance, 0, 0) ; if ( vtMove.x > dMaxW) dMaxW = vtMove.x ; // ciclo di pulizia for ( auto iIter = lstPC.begin() ; iIter != lstPC.end() ; ++ iIter) delete (*iIter) ; lstPC.clear() ; } // sistemazioni per la posizione del punto di inserimento Vector3d vtIpMove = GetTextInsertPointMove( dMaxW, dHCap, dMinH, nInsPos) ; for ( auto& PA : lstPA) PA.Translate( vtIpMove) ; // inverto i poliarchi per avere gli esterni CCW for ( auto& PA : lstPA) PA.Invert() ; // ripristino il font originale SelectObject( m_hDC, hPrevFont) ; return true ; } //---------------------------------------------------------------------------- bool OsFont::GetTextLines( const string& sText, int nInsPos, PNTVECTOR& vPt, STRVECTOR& vLine) const { // pulisco i parametri di ritorno vPt.clear() ; vLine.clear() ; // verifico esistenza font corrente if ( m_hDC == nullptr || m_hFont == nullptr || m_sFont.empty()) return false ; // rendo corrente il font HFONT hPrevFont = (HFONT) SelectObject( m_hDC, m_hFont) ; if ( hPrevFont == nullptr) 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) ; // ciclo sui 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]) ; // recupero l'advance double dAdvance ; if ( ! GetCharAdvance( vCode[i], dAdvance)) return false ; // aggiorno lo spostamento 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) ; // ripristino il font originale SelectObject( m_hDC, hPrevFont) ; return true ; } //---------------------------------------------------------------------------- double DoubleFromFixed( FIXED fx) { return ( double( fx.value) + double( fx.fract) * ( 1.0 / 65536.0)) ; } //---------------------------------------------------------------------------- FIXED MediaTwoFixed( FIXED fx1, FIXED fx2) { long l = 0L ; l = (*((long*)&(fx1)) + *((long*)&(fx2))) / 2L ; return (*(FIXED*)&l) ; } //---------------------------------------------------------------------------- bool OsFont::GetCharAdvance( unsigned int nChar, double& dAdvance) const { GLYPHMETRICS gm ; MAT2 mat = { {0,1},{0,0},{0,0},{0,1}} ; // recupero la dimensione necessaria del buffer e lo alloco DWORD dwSize = GetGlyphOutlineW( m_hDC, nChar, GGO_NATIVE, &gm, 0, NULL, &mat) ; if ( dwSize == GDI_ERROR) return false ; // assegno l'avanzamento al prossimo carattere dAdvance = gm.gmCellIncX ; return true ; } //---------------------------------------------------------------------------- bool OsFont::GetCharOutline( unsigned int nChar, double& dAdvance, ICURVEPLIST& lstPC) const { GLYPHMETRICS gm ; MAT2 mat = { {0,1},{0,0},{0,0},{0,1}} ; // recupero la dimensione necessaria del buffer e lo alloco DWORD dwSize = GetGlyphOutlineW( m_hDC, nChar, GGO_NATIVE, &gm, 0, NULL, &mat) ; if ( dwSize == GDI_ERROR) return false ; PtrOwner pBuffer( new( nothrow) char[dwSize]) ; if ( IsNull( pBuffer)) return false ; // recupero l'outline DWORD dErr = GetGlyphOutlineW( m_hDC, nChar, GGO_NATIVE, &gm, dwSize, pBuffer, &mat) ; if ( dErr == GDI_ERROR) return false ; // assegno l'avanzamento al prossimo carattere dAdvance = gm.gmCellIncX ; // mentre esistono nuovi contorni LPTTPOLYGONHEADER pHeader = (LPTTPOLYGONHEADER) ::Get( pBuffer) ; while ( (LPSTR) pHeader < ( pBuffer + ptrdiff_t( dwSize))) { // leggo un nuovo contorno if ( pHeader->dwType == TT_POLYGON_TYPE) { // creo curva composita PtrOwner pCCompo( CreateBasicCurveComposite()) ; if ( IsNull( pCCompo)) return false ; // posizionamento sul punto iniziale Point3d ptFirst( DoubleFromFixed( pHeader->pfxStart.x), DoubleFromFixed( pHeader->pfxStart.y), 0) ; Point3d ptLast = ptFirst ; // puntatore alla prima polycurva LPTTPOLYCURVE pCurve = (LPTTPOLYCURVE)( pHeader + 1) ; // mentre esistono polycurve while ( (LPSTR) pCurve < ( (LPSTR) pHeader + ptrdiff_t( pHeader->cb))) { // numero punti int nPnt = pCurve->cpfx ; // se rette if ( pCurve->wType == TT_PRIM_LINE) { for ( int i = 0 ; i < nPnt ; ++ i ) { Point3d ptP( DoubleFromFixed( pCurve->apfx[i].x), DoubleFromFixed( pCurve->apfx[i].y), 0) ; if ( ! AreSamePointApprox( ptLast, ptP)) { // aggiungo la retta alla curva composita if ( ! AddLineToCompo( pCCompo, ptLast, ptP)) return false ; // salvo punto come ultimo ptLast = ptP ; } } } // se curve di Bezier quadratiche else if ( pCurve->wType == TT_PRIM_QSPLINE) { for ( int i = 0 ; i < nPnt - 1 ; ++ i ) { // punto medio CBezier Point3d ptM( DoubleFromFixed( pCurve->apfx[i].x), DoubleFromFixed( pCurve->apfx[i].y), 0) ; // punto finale CBezier POINTFX pfEnd ; // se non è alla fine è il medio dei due punti adiacenti del poligono if ( i < ( nPnt - 2)) { pfEnd.x = MediaTwoFixed( pCurve->apfx[i].x, pCurve->apfx[i+1].x) ; pfEnd.y = MediaTwoFixed( pCurve->apfx[i].y, pCurve->apfx[i+1].y) ; } else pfEnd = pCurve->apfx[i+1] ; Point3d ptE( DoubleFromFixed( pfEnd.x), DoubleFromFixed( pfEnd.y), 0) ; // aggiungo la curva di Bezier quadratica alla curva composita if ( ! AddCBezierQuadToCompo( pCCompo, ptLast, ptM, ptE)) return false ; // salvo punto finale come ultimo ptLast = ptE ; } } // altrimenti errore else { return false ; } // si passa alla polycurva successiva pCurve = (LPTTPOLYCURVE) &( pCurve->apfx[nPnt]) ; } // si aggiunge, se necessario, una linea retta per chiudere la curva if ( ! AreSamePointApprox( ptFirst, ptLast)) { // aggiungo la retta alla curva composita if ( ! AddLineToCompo( pCCompo, ptLast, ptFirst)) return false ; // salvo ultimo punto ptLast = ptFirst ; } // se curva composita ok, la inserisco in lista if ( pCCompo->IsValid()) lstPC.push_back( ::Release( pCCompo)) ; } // mi sposto sul prossimo contorno pHeader = (LPTTPOLYGONHEADER) ( (LPSTR) pHeader + ptrdiff_t( pHeader->cb)) ; } return true ; } //---------------------------------------------------------------------------- bool OsFont::AddLineToCompo( ICurveComposite* pCCompo, const Point3d& ptStart, const Point3d& ptEnd) const { // verifico curva composita if ( pCCompo == nullptr) return false ; // creo retta, la imposto e la inserisco nella curva composita PtrOwner pCLine( CreateBasicCurveLine()) ; if ( IsNull( pCLine)) return false ; if ( ! pCLine->Set( ptStart, ptEnd)) return false ; if ( ! pCCompo->AddCurve( ::Release( pCLine))) return false ; return true ; } //---------------------------------------------------------------------------- bool OsFont::AddCBezierQuadToCompo( ICurveComposite* pCCompo, const Point3d& ptStart, const Point3d& ptMid, const Point3d& ptEnd) const { // verifico curva composita if ( pCCompo == nullptr) return false ; // creo curva di Bezier quadratica, la imposto e la inserisco nella curva composita PtrOwner pCBezier( CreateBasicCurveBezier()) ; if ( IsNull( pCBezier)) return false ; if ( ! pCBezier->Init( 2, false) || ! pCBezier->SetControlPoint( 0, ptStart) || ! pCBezier->SetControlPoint( 1, ptMid) || ! pCBezier->SetControlPoint( 2, ptEnd)) return false ; if ( ! pCCompo->AddCurve( ::Release( pCBezier))) return false ; return true ; }