Commit 6be27ae2 authored by Maciej Suminski's avatar Maciej Suminski
Browse files

Glyphs and their bounding boxes are held in vectors instead of deque.

Moved scaling of font glyphs to the moment when they are created (eliminated a few multiplications unnecessary variables).
Changed some magic numbers into constants.
parent ca11855f
Loading
Loading
Loading
Loading
+100 −81
Original line number Diff line number Diff line
@@ -30,9 +30,9 @@

using namespace KIGFX;


const double STROKE_FONT::LINE_HEIGHT_RATIO  = 1.6;

const double STROKE_FONT::OVERBAR_HEIGHT = 0.45;
const double STROKE_FONT::BOLD_FACTOR = 1.3;
const double STROKE_FONT::HERSHEY_SCALE = 1.0 / 21.0;

STROKE_FONT::STROKE_FONT( GAL* aGal ) :
    m_gal( aGal ),
@@ -41,7 +41,6 @@ STROKE_FONT::STROKE_FONT( GAL* aGal ) :
    m_mirrored( false )
{
    // Default values
    m_scaleFactor = 1.0 / 21.0;
    m_glyphSize = VECTOR2D( 10.0, 10.0 );
    m_verticalJustify   = GR_TEXT_VJUSTIFY_BOTTOM;
    m_horizontalJustify = GR_TEXT_HJUSTIFY_LEFT;
@@ -57,6 +56,8 @@ bool STROKE_FONT::LoadNewStrokeFont( const char* const aNewStrokeFont[], int aNe
{
    m_glyphs.clear();
    m_glyphBoundingBoxes.clear();
    m_glyphs.resize( aNewStrokeFontSize );
    m_glyphBoundingBoxes.resize( aNewStrokeFontSize );

    for( int j = 0; j < aNewStrokeFontSize; j++ )
    {
@@ -82,8 +83,8 @@ bool STROKE_FONT::LoadNewStrokeFont( const char* const aNewStrokeFont[], int aNe
            if( i < 2 )
            {
                // The first two values contain the width of the char
                glyphStartX     = coordinate[0] - 'R';
                glyphEndX       = coordinate[1] - 'R';
                glyphStartX     = ( coordinate[0] - 'R' ) * HERSHEY_SCALE;
                glyphEndX       = ( coordinate[1] - 'R' ) * HERSHEY_SCALE;
                glyphBoundingX  = VECTOR2D( 0, glyphEndX - glyphStartX );
            }
            else if( ( coordinate[0] == ' ' ) && ( coordinate[1] == 'R' ) )
@@ -98,8 +99,8 @@ bool STROKE_FONT::LoadNewStrokeFont( const char* const aNewStrokeFont[], int aNe
            {
                // Every coordinate description of the Hershey format has an offset,
                // it has to be subtracted
                point.x = (double) ( coordinate[0] - 'R' ) - glyphStartX;
                point.y = (double) ( coordinate[1] - 'R' ) - 11.0;
                point.x = (double) ( coordinate[0] - 'R' ) * HERSHEY_SCALE - glyphStartX;
                point.y = (double) ( coordinate[1] - 'R' ) * HERSHEY_SCALE;
                pointList.push_back( point );
            }

@@ -109,16 +110,22 @@ bool STROKE_FONT::LoadNewStrokeFont( const char* const aNewStrokeFont[], int aNe
        if( pointList.size() > 0 )
            glyph.push_back( pointList );

        m_glyphs.push_back( glyph );
        m_glyphs[j] = glyph;

        // Compute the bounding box of the glyph
        m_glyphBoundingBoxes.push_back( computeBoundingBox( glyph, glyphBoundingX ) );
        m_glyphBoundingBoxes[j] = computeBoundingBox( glyph, glyphBoundingX );
    }

    return true;
}


int STROKE_FONT::getInterline() const
{
    return ( m_glyphSize.y * 14 ) / 10 + m_gal->GetLineWidth();
}


BOX2D STROKE_FONT::computeBoundingBox( const GLYPH& aGLYPH, const VECTOR2D& aGLYPHBoundingX ) const
{
    BOX2D boundingBox;
@@ -145,115 +152,134 @@ BOX2D STROKE_FONT::computeBoundingBox( const GLYPH& aGLYPH, const VECTOR2D& aGLY

void STROKE_FONT::Draw( wxString aText, const VECTOR2D& aPosition, double aRotationAngle )
{
    // By default overbar is turned off
    m_overbar = false;

    // Context needs to be saved before any transformations
    m_gal->Save();

    m_gal->Translate( aPosition );

    // Single line height
    int lineHeight = getInterline();

    // The overall height of all lines of text
    double textBlockHeight = lineHeight * ( linesCount( aText ) - 1 );

    switch( m_verticalJustify )
    {
    case GR_TEXT_VJUSTIFY_CENTER:
        m_gal->Translate( VECTOR2D( 0, -textBlockHeight / 2.0 ) );
        break;

    case GR_TEXT_VJUSTIFY_BOTTOM:
        m_gal->Translate( VECTOR2D( 0, -textBlockHeight ) );
        break;

    case GR_TEXT_VJUSTIFY_TOP:
        break;

    default:
        break;
    }

    m_gal->Rotate( -aRotationAngle );

    m_gal->SetIsStroke( true );
    m_gal->SetIsFill( false );

    if( m_bold )
        m_gal->SetLineWidth( m_gal->GetLineWidth() * BOLD_FACTOR );

    // Split multiline strings into separate ones and draw them line by line
    int newlinePos = aText.Find( '\n' );
    int begin = 0;
    int newlinePos = aText.find( '\n' );

    if( newlinePos != wxNOT_FOUND )
    while( newlinePos != wxNOT_FOUND )
    {
        VECTOR2D nextlinePosition = VECTOR2D( 0.0, m_glyphSize.y * LINE_HEIGHT_RATIO );
        size_t length = newlinePos - begin;
        drawSingleLineText( aText.Mid( begin, length ) );
        m_gal->Translate( VECTOR2D( 0.0, lineHeight ) );

        begin = newlinePos + 1;
        newlinePos = aText.find( '\n', begin + 1 );
    }

        Draw( aText.Mid( newlinePos + 1 ), nextlinePosition, 0.0 );
        aText = aText.Mid( 0, newlinePos );
    // Draw the last (or the only one) line
    drawSingleLineText( aText.Mid( begin ) );

    m_gal->Restore();
}


void STROKE_FONT::drawSingleLineText( const wxString& aText )
{
    // By default the overbar is turned off
    m_overbar = false;

    double xOffset;
    VECTOR2D glyphSize( m_glyphSize );

    // Compute the text size
    VECTOR2D textsize = computeTextSize( aText );
    VECTOR2D textSize = computeTextSize( aText );

    m_gal->Save();

    // Adjust the text position to the given alignment
    switch( m_horizontalJustify )
    {
    case GR_TEXT_HJUSTIFY_CENTER:
        m_gal->Translate( VECTOR2D( -textsize.x / 2.0, 0 ) );
        m_gal->Translate( VECTOR2D( -textSize.x / 2.0, 0 ) );
        break;

    case GR_TEXT_HJUSTIFY_RIGHT:
        if( !m_mirrored )
            m_gal->Translate( VECTOR2D( -textsize.x, 0 ) );

            m_gal->Translate( VECTOR2D( -textSize.x, 0 ) );
        break;

    case GR_TEXT_HJUSTIFY_LEFT:
        if( m_mirrored )
            m_gal->Translate( VECTOR2D( -textsize.x, 0 ) );

        break;

    default:
        break;
    }

    switch( m_verticalJustify )
    {
    case GR_TEXT_VJUSTIFY_CENTER:
        m_gal->Translate( VECTOR2D( 0, textsize.y / 2.0 ) );
        break;

    case GR_TEXT_VJUSTIFY_TOP:
        m_gal->Translate( VECTOR2D( 0, textsize.y ) );
        break;

    case GR_TEXT_VJUSTIFY_BOTTOM:
            m_gal->Translate( VECTOR2D( -textSize.x, 0 ) );
        break;

    default:
        break;
    }

    double xOffset, glyphSizeX;

    if( m_mirrored )
    {
        // In case of mirrored text invert the X scale of points and their X direction
        // (m_glyphSize.x) and start drawing from the position where text normally should end
        // (textsize.x)
        xOffset     = textsize.x;
        glyphSizeX  = -m_glyphSize.x;
    }
    else
        // (textSize.x)
        xOffset = textSize.x;
        glyphSize.x = -m_glyphSize.x;
    } else
    {
        xOffset = 0.0;
        glyphSizeX  = m_glyphSize.x;
    }
    double scaleY = m_scaleFactor * m_glyphSize.y;
    double scaleX = m_scaleFactor * glyphSizeX;

    m_gal->SetIsStroke( true );
    m_gal->SetIsFill( false );

    if( m_bold )
    {
        m_gal->SetLineWidth( m_gal->GetLineWidth() * 1.3 );
    }

    for( wxString::const_iterator chIt = aText.begin(); chIt != aText.end(); chIt++ )
    {
        // Toggle overbar
        if( *chIt == '~' )
        {
            m_overbar = !m_overbar;
            continue;
        }

        GLYPH_LIST::iterator glyphIt = m_glyphs.begin();
        std::deque<BOX2D>::iterator bbIt = m_glyphBoundingBoxes.begin();

        unsigned dd = *chIt - ' ';

        if( dd >= m_glyphBoundingBoxes.size() )
        if( dd >= m_glyphBoundingBoxes.size() || dd < 0 )
            dd = '?' - ' ';

        advance( glyphIt, dd );
        advance( bbIt, dd );
        GLYPH& glyph = m_glyphs[dd];
        BOX2D& bbox = m_glyphBoundingBoxes[dd];

        GLYPH glyph = *glyphIt;
        if( m_overbar )
        {
            VECTOR2D startOverbar( xOffset, -getInterline() * OVERBAR_HEIGHT );
            VECTOR2D endOverbar( xOffset + glyphSize.x * bbox.GetEnd().x,
                                 -getInterline() * OVERBAR_HEIGHT );
            m_gal->DrawLine( startOverbar, endOverbar );
        }

        for( GLYPH::iterator pointListIt = glyph.begin(); pointListIt != glyph.end();
             pointListIt++ )
@@ -263,7 +289,7 @@ void STROKE_FONT::Draw( wxString aText, const VECTOR2D& aPosition, double aRotat
            for( std::deque<VECTOR2D>::iterator pointIt = pointListIt->begin();
                 pointIt != pointListIt->end(); pointIt++ )
            {
                VECTOR2D pointPos( pointIt->x * scaleX + xOffset, pointIt->y * scaleY );
                VECTOR2D pointPos( pointIt->x * glyphSize.x + xOffset, pointIt->y * glyphSize.y );

                if( m_italic )
                {
@@ -278,15 +304,7 @@ void STROKE_FONT::Draw( wxString aText, const VECTOR2D& aPosition, double aRotat
            m_gal->DrawPolyline( pointListScaled );
        }

        if( m_overbar )
        {
            VECTOR2D startOverbar( xOffset, -textsize.y * 1.2 );
            VECTOR2D endOverbar( xOffset + m_scaleFactor * glyphSizeX * bbIt->GetEnd().x,
                                 -textsize.y * 1.2 );
            m_gal->DrawLine( startOverbar, endOverbar );
        }

        xOffset += m_scaleFactor * glyphSizeX * bbIt->GetEnd().x;
        xOffset += glyphSize.x * bbox.GetEnd().x;
    }

    m_gal->Restore();
@@ -299,18 +317,19 @@ VECTOR2D STROKE_FONT::computeTextSize( const wxString& aText ) const

    for( wxString::const_iterator chIt = aText.begin(); chIt != aText.end(); chIt++ )
    {
        wxASSERT_MSG( *chIt != '\n',
                      wxT( "This function is intended to work with single line strings" ) );

        if( *chIt == '~' )
            continue;

        std::deque<BOX2D>::const_iterator bbIt = m_glyphBoundingBoxes.begin();
        // Index in the bounding boxes table
        unsigned dd = *chIt - ' ';

        if( dd >= m_glyphBoundingBoxes.size() )
        if( dd >= m_glyphBoundingBoxes.size() || dd < 0 )
            dd = '?' - ' ';

        advance( bbIt, dd );

        result.x += m_scaleFactor * m_glyphSize.x * bbIt->GetEnd().x;
        result.x += m_glyphSize.x * m_glyphBoundingBoxes[dd].GetEnd().x;
    }

    return result;
+45 −16
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ namespace KIGFX
class GAL;

typedef std::deque< std::deque<VECTOR2D> > GLYPH;
typedef std::deque<GLYPH>                  GLYPH_LIST;
typedef std::vector<GLYPH>                 GLYPH_LIST;

/**
 * @brief Class STROKE_FONT implements stroke font drawing.
@@ -55,8 +55,6 @@ public:
    /// Destructor
    ~STROKE_FONT();

    // TODO Load font from a text file

    /**
     * @brief Load the new stroke font.
     *
@@ -75,16 +73,6 @@ public:
     */
    void Draw( wxString aText, const VECTOR2D& aPosition, double aRotationAngle );

    /**
     * @brief Set the scale factor of the font for the glyph size.
     *
     * @param aScaleFactor is the scale factor of the font.
     */
    inline void SetScaleFactor( const double aScaleFactor )
    {
        m_scaleFactor = aScaleFactor;
    }

    /**
     * @brief Set the glyph size.
     *
@@ -158,13 +146,19 @@ public:
private:
    GAL*                m_gal;                                    ///< Pointer to the GAL
    GLYPH_LIST          m_glyphs;                                 ///< Glyph list
    std::deque<BOX2D>   m_glyphBoundingBoxes;                     ///< Bounding boxes of the glyphs
    double              m_scaleFactor;                            ///< Scale factor for the glyph
    std::vector<BOX2D>  m_glyphBoundingBoxes;                     ///< Bounding boxes of the glyphs
    VECTOR2D            m_glyphSize;                              ///< Size of the glyphs
    EDA_TEXT_HJUSTIFY_T m_horizontalJustify;                      ///< Horizontal justification
    EDA_TEXT_VJUSTIFY_T m_verticalJustify;                        ///< Vertical justification
    bool                m_bold, m_italic, m_mirrored, m_overbar;  ///< Properties of text

    /**
     * @brief Returns a single line height using current settings.
     *
     * @return The line height.
     */
    int getInterline() const;

    /**
     * @brief Compute the bounding box of a given glyph.
     *
@@ -174,6 +168,14 @@ private:
     */
    BOX2D computeBoundingBox( const GLYPH& aGlyph, const VECTOR2D& aGlyphBoundingX ) const;

    /**
     * @brief Draws a single line of text. Multiline texts should be split before using the
     * function.
     *
     * @param aText is the text to be drawn.
     */
    void drawSingleLineText( const wxString& aText );

    /**
     * @brief Compute the size of a given text.
     *
@@ -182,7 +184,34 @@ private:
     */
    VECTOR2D computeTextSize( const wxString& aText ) const;

    static const double LINE_HEIGHT_RATIO;
    /**
     * @brief Returns number of lines for a given text.
     *
     * @param aText is the text to be checked.
     * @return Number of lines of aText.
     */
    unsigned int linesCount( const wxString& aText ) const
    {
        wxString::const_iterator it, itEnd;
        unsigned int lines = 1;

        for( it = aText.begin(), itEnd = aText.end(); it != itEnd; ++it )
        {
            if( *it == '\n' )
                ++lines;
        }

        return lines;
    }

    ///> Factor that determines relative height of overbar.
    static const double OVERBAR_HEIGHT;

    ///> Factor that determines relative line width for bold text.
    static const double BOLD_FACTOR;

    ///> Scale factor for the glyph
    static const double HERSHEY_SCALE;
};
} // namespace KIGFX