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.
This commit is contained in:
Maciej Suminski 2013-12-05 16:29:54 +01:00
parent ca11855f12
commit 6be27ae2ea
2 changed files with 158 additions and 110 deletions

View File

@ -30,9 +30,9 @@
using namespace KIGFX; using namespace KIGFX;
const double STROKE_FONT::OVERBAR_HEIGHT = 0.45;
const double STROKE_FONT::LINE_HEIGHT_RATIO = 1.6; const double STROKE_FONT::BOLD_FACTOR = 1.3;
const double STROKE_FONT::HERSHEY_SCALE = 1.0 / 21.0;
STROKE_FONT::STROKE_FONT( GAL* aGal ) : STROKE_FONT::STROKE_FONT( GAL* aGal ) :
m_gal( aGal ), m_gal( aGal ),
@ -41,7 +41,6 @@ STROKE_FONT::STROKE_FONT( GAL* aGal ) :
m_mirrored( false ) m_mirrored( false )
{ {
// Default values // Default values
m_scaleFactor = 1.0 / 21.0;
m_glyphSize = VECTOR2D( 10.0, 10.0 ); m_glyphSize = VECTOR2D( 10.0, 10.0 );
m_verticalJustify = GR_TEXT_VJUSTIFY_BOTTOM; m_verticalJustify = GR_TEXT_VJUSTIFY_BOTTOM;
m_horizontalJustify = GR_TEXT_HJUSTIFY_LEFT; m_horizontalJustify = GR_TEXT_HJUSTIFY_LEFT;
@ -57,6 +56,8 @@ bool STROKE_FONT::LoadNewStrokeFont( const char* const aNewStrokeFont[], int aNe
{ {
m_glyphs.clear(); m_glyphs.clear();
m_glyphBoundingBoxes.clear(); m_glyphBoundingBoxes.clear();
m_glyphs.resize( aNewStrokeFontSize );
m_glyphBoundingBoxes.resize( aNewStrokeFontSize );
for( int j = 0; j < aNewStrokeFontSize; j++ ) for( int j = 0; j < aNewStrokeFontSize; j++ )
{ {
@ -82,8 +83,8 @@ bool STROKE_FONT::LoadNewStrokeFont( const char* const aNewStrokeFont[], int aNe
if( i < 2 ) if( i < 2 )
{ {
// The first two values contain the width of the char // The first two values contain the width of the char
glyphStartX = coordinate[0] - 'R'; glyphStartX = ( coordinate[0] - 'R' ) * HERSHEY_SCALE;
glyphEndX = coordinate[1] - 'R'; glyphEndX = ( coordinate[1] - 'R' ) * HERSHEY_SCALE;
glyphBoundingX = VECTOR2D( 0, glyphEndX - glyphStartX ); glyphBoundingX = VECTOR2D( 0, glyphEndX - glyphStartX );
} }
else if( ( coordinate[0] == ' ' ) && ( coordinate[1] == 'R' ) ) 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, // Every coordinate description of the Hershey format has an offset,
// it has to be subtracted // it has to be subtracted
point.x = (double) ( coordinate[0] - 'R' ) - glyphStartX; point.x = (double) ( coordinate[0] - 'R' ) * HERSHEY_SCALE - glyphStartX;
point.y = (double) ( coordinate[1] - 'R' ) - 11.0; point.y = (double) ( coordinate[1] - 'R' ) * HERSHEY_SCALE;
pointList.push_back( point ); pointList.push_back( point );
} }
@ -109,16 +110,22 @@ bool STROKE_FONT::LoadNewStrokeFont( const char* const aNewStrokeFont[], int aNe
if( pointList.size() > 0 ) if( pointList.size() > 0 )
glyph.push_back( pointList ); glyph.push_back( pointList );
m_glyphs.push_back( glyph ); m_glyphs[j] = glyph;
// Compute the bounding box of the glyph // Compute the bounding box of the glyph
m_glyphBoundingBoxes.push_back( computeBoundingBox( glyph, glyphBoundingX ) ); m_glyphBoundingBoxes[j] = computeBoundingBox( glyph, glyphBoundingX );
} }
return true; 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 STROKE_FONT::computeBoundingBox( const GLYPH& aGLYPH, const VECTOR2D& aGLYPHBoundingX ) const
{ {
BOX2D boundingBox; 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 ) 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 // Context needs to be saved before any transformations
m_gal->Save(); m_gal->Save();
m_gal->Translate( aPosition ); m_gal->Translate( aPosition );
m_gal->Rotate( -aRotationAngle );
// Split multiline strings into separate ones and draw them line by line // Single line height
int newlinePos = aText.Find( '\n' ); int lineHeight = getInterline();
if( newlinePos != wxNOT_FOUND ) // The overall height of all lines of text
{ double textBlockHeight = lineHeight * ( linesCount( aText ) - 1 );
VECTOR2D nextlinePosition = VECTOR2D( 0.0, m_glyphSize.y * LINE_HEIGHT_RATIO );
Draw( aText.Mid( newlinePos + 1 ), nextlinePosition, 0.0 );
aText = aText.Mid( 0, newlinePos );
}
// Compute the text size
VECTOR2D textsize = computeTextSize( aText );
// 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 ) );
break;
case GR_TEXT_HJUSTIFY_RIGHT:
if( !m_mirrored )
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 ) switch( m_verticalJustify )
{ {
case GR_TEXT_VJUSTIFY_CENTER: case GR_TEXT_VJUSTIFY_CENTER:
m_gal->Translate( VECTOR2D( 0, textsize.y / 2.0 ) ); m_gal->Translate( VECTOR2D( 0, -textBlockHeight / 2.0 ) );
break;
case GR_TEXT_VJUSTIFY_TOP:
m_gal->Translate( VECTOR2D( 0, textsize.y ) );
break; break;
case GR_TEXT_VJUSTIFY_BOTTOM: case GR_TEXT_VJUSTIFY_BOTTOM:
m_gal->Translate( VECTOR2D( 0, -textBlockHeight ) );
break;
case GR_TEXT_VJUSTIFY_TOP:
break; break;
default: default:
break; break;
} }
double xOffset, glyphSizeX; m_gal->Rotate( -aRotationAngle );
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
{
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->SetIsStroke( true );
m_gal->SetIsFill( false ); m_gal->SetIsFill( false );
if( m_bold ) if( m_bold )
m_gal->SetLineWidth( m_gal->GetLineWidth() * BOLD_FACTOR );
// Split multiline strings into separate ones and draw them line by line
int begin = 0;
int newlinePos = aText.find( '\n' );
while( newlinePos != wxNOT_FOUND )
{ {
m_gal->SetLineWidth( m_gal->GetLineWidth() * 1.3 ); 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 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 );
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 ) );
break;
case GR_TEXT_HJUSTIFY_RIGHT:
if( !m_mirrored )
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;
}
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;
glyphSize.x = -m_glyphSize.x;
} else
{
xOffset = 0.0;
} }
for( wxString::const_iterator chIt = aText.begin(); chIt != aText.end(); chIt++ ) for( wxString::const_iterator chIt = aText.begin(); chIt != aText.end(); chIt++ )
{ {
// Toggle overbar
if( *chIt == '~' ) if( *chIt == '~' )
{ {
m_overbar = !m_overbar; m_overbar = !m_overbar;
continue; continue;
} }
GLYPH_LIST::iterator glyphIt = m_glyphs.begin();
std::deque<BOX2D>::iterator bbIt = m_glyphBoundingBoxes.begin();
unsigned dd = *chIt - ' '; unsigned dd = *chIt - ' ';
if( dd >= m_glyphBoundingBoxes.size() ) if( dd >= m_glyphBoundingBoxes.size() || dd < 0 )
dd = '?' - ' '; dd = '?' - ' ';
advance( glyphIt, dd ); GLYPH& glyph = m_glyphs[dd];
advance( bbIt, 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(); for( GLYPH::iterator pointListIt = glyph.begin(); pointListIt != glyph.end();
pointListIt++ ) pointListIt++ )
@ -263,7 +289,7 @@ void STROKE_FONT::Draw( wxString aText, const VECTOR2D& aPosition, double aRotat
for( std::deque<VECTOR2D>::iterator pointIt = pointListIt->begin(); for( std::deque<VECTOR2D>::iterator pointIt = pointListIt->begin();
pointIt != pointListIt->end(); pointIt++ ) 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 ) if( m_italic )
{ {
@ -278,15 +304,7 @@ void STROKE_FONT::Draw( wxString aText, const VECTOR2D& aPosition, double aRotat
m_gal->DrawPolyline( pointListScaled ); m_gal->DrawPolyline( pointListScaled );
} }
if( m_overbar ) xOffset += glyphSize.x * bbox.GetEnd().x;
{
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;
} }
m_gal->Restore(); 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++ ) 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 == '~' ) if( *chIt == '~' )
continue; continue;
std::deque<BOX2D>::const_iterator bbIt = m_glyphBoundingBoxes.begin(); // Index in the bounding boxes table
unsigned dd = *chIt - ' '; unsigned dd = *chIt - ' ';
if( dd >= m_glyphBoundingBoxes.size() ) if( dd >= m_glyphBoundingBoxes.size() || dd < 0 )
dd = '?' - ' '; dd = '?' - ' ';
advance( bbIt, dd ); result.x += m_glyphSize.x * m_glyphBoundingBoxes[dd].GetEnd().x;
result.x += m_scaleFactor * m_glyphSize.x * bbIt->GetEnd().x;
} }
return result; return result;

View File

@ -39,7 +39,7 @@ namespace KIGFX
class GAL; class GAL;
typedef std::deque< std::deque<VECTOR2D> > GLYPH; 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. * @brief Class STROKE_FONT implements stroke font drawing.
@ -55,8 +55,6 @@ public:
/// Destructor /// Destructor
~STROKE_FONT(); ~STROKE_FONT();
// TODO Load font from a text file
/** /**
* @brief Load the new stroke font. * @brief Load the new stroke font.
* *
@ -75,16 +73,6 @@ public:
*/ */
void Draw( wxString aText, const VECTOR2D& aPosition, double aRotationAngle ); 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. * @brief Set the glyph size.
* *
@ -158,13 +146,19 @@ public:
private: private:
GAL* m_gal; ///< Pointer to the GAL GAL* m_gal; ///< Pointer to the GAL
GLYPH_LIST m_glyphs; ///< Glyph list GLYPH_LIST m_glyphs; ///< Glyph list
std::deque<BOX2D> m_glyphBoundingBoxes; ///< Bounding boxes of the glyphs std::vector<BOX2D> m_glyphBoundingBoxes; ///< Bounding boxes of the glyphs
double m_scaleFactor; ///< Scale factor for the glyph
VECTOR2D m_glyphSize; ///< Size of the glyphs VECTOR2D m_glyphSize; ///< Size of the glyphs
EDA_TEXT_HJUSTIFY_T m_horizontalJustify; ///< Horizontal justification EDA_TEXT_HJUSTIFY_T m_horizontalJustify; ///< Horizontal justification
EDA_TEXT_VJUSTIFY_T m_verticalJustify; ///< Vertical justification EDA_TEXT_VJUSTIFY_T m_verticalJustify; ///< Vertical justification
bool m_bold, m_italic, m_mirrored, m_overbar; ///< Properties of text 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. * @brief Compute the bounding box of a given glyph.
* *
@ -174,6 +168,14 @@ private:
*/ */
BOX2D computeBoundingBox( const GLYPH& aGlyph, const VECTOR2D& aGlyphBoundingX ) const; 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. * @brief Compute the size of a given text.
* *
@ -182,7 +184,34 @@ private:
*/ */
VECTOR2D computeTextSize( const wxString& aText ) const; 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 } // namespace KIGFX