KiCad PCB EDA Suite
Loading...
Searching...
No Matches
stroke_font.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KICAD, a free EDA CAD application.
3 *
4 * Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
5 * Copyright (C) 2013 CERN
6 * @author Maciej Suminski <[email protected]>
7 * Copyright (C) 2016-2023 Kicad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, you may find one here:
21 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22 * or you may search the http://www.gnu.org website for the version 2 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
28#include <wx/string.h>
29#include <wx/textfile.h>
30#include <newstroke_font.h>
31#include <font/glyph.h>
32#include <font/stroke_font.h>
34#include <trigo.h>
35
36// The "official" name of the building Kicad stroke font (always existing)
38
39#include <mutex>
40
41using namespace KIFONT;
42
43
45static constexpr double STROKE_FONT_SCALE = 1.0 / 21.0;
46
48static constexpr int FONT_OFFSET = -8;
49
50
52std::vector<std::shared_ptr<GLYPH>> g_defaultFontGlyphs;
55
56
58 m_glyphs( nullptr ),
59 m_glyphBoundingBoxes( nullptr ),
60 m_maxGlyphWidth( 0.0 )
61{
62}
63
64
65STROKE_FONT* STROKE_FONT::LoadFont( const wxString& aFontName )
66{
67 if( aFontName.empty() )
68 {
69 STROKE_FONT* font = new STROKE_FONT();
71 return font;
72 }
73 else
74 {
75 // FONT TODO: support for other stroke fonts?
76 return nullptr;
77 }
78}
79
80
81void buildGlyphBoundingBox( std::shared_ptr<STROKE_GLYPH>& aGlyph, double aGlyphWidth )
82{
83 VECTOR2D min( 0, 0 );
84 VECTOR2D max( aGlyphWidth, 0 );
85
86 for( const std::vector<VECTOR2D>& pointList : *aGlyph )
87 {
88 for( const VECTOR2D& point : pointList )
89 {
90 min.y = std::min( min.y, point.y );
91 max.y = std::max( max.y, point.y );
92 }
93 }
94
95 aGlyph->SetBoundingBox( BOX2D( min, max - min ) );
96}
97
98
99void STROKE_FONT::loadNewStrokeFont( const char* const aNewStrokeFont[], int aNewStrokeFontSize )
100{
101 // Protect the initialization sequence against multiple entries
102 std::lock_guard<std::mutex> lock( g_defaultFontLoadMutex );
103
105 {
106 g_defaultFontGlyphs.reserve( aNewStrokeFontSize );
107
108 g_defaultFontGlyphBoundingBoxes = new std::vector<BOX2D>;
109 g_defaultFontGlyphBoundingBoxes->reserve( aNewStrokeFontSize );
110
111 for( int j = 0; j < aNewStrokeFontSize; j++ )
112 {
113 std::shared_ptr<STROKE_GLYPH> glyph = std::make_shared<STROKE_GLYPH>();
114
115 double glyphStartX = 0.0;
116 double glyphEndX = 0.0;
117 double glyphWidth = 0.0;
118 int strokes = 0;
119 int i = 0;
120
121 while( aNewStrokeFont[j][i] )
122 {
123 if( aNewStrokeFont[j][i] == ' ' && aNewStrokeFont[j][i+1] == 'R' )
124 strokes++;
125
126 i += 2;
127 }
128
129 glyph->reserve( strokes + 1 );
130
131 i = 0;
132
133 while( aNewStrokeFont[j][i] )
134 {
135 VECTOR2D point( 0.0, 0.0 );
136 char coordinate[2] = { 0, };
137
138 for( int k : { 0, 1 } )
139 coordinate[k] = aNewStrokeFont[j][i + k];
140
141 if( i < 2 )
142 {
143 // The first two values contain the width of the char
144 glyphStartX = ( coordinate[0] - 'R' ) * STROKE_FONT_SCALE;
145 glyphEndX = ( coordinate[1] - 'R' ) * STROKE_FONT_SCALE;
146 glyphWidth = glyphEndX - glyphStartX;
147 }
148 else if( ( coordinate[0] == ' ' ) && ( coordinate[1] == 'R' ) )
149 {
150 glyph->RaisePen();
151 }
152 else
153 {
154 // In stroke font, coordinates values are coded as <value> + 'R', where
155 // <value> is an ASCII char.
156 // therefore every coordinate description of the Hershey format has an offset,
157 // it has to be subtracted
158 // Note:
159 // * the stroke coordinates are stored in reduced form (-1.0 to +1.0),
160 // and the actual size is stroke coordinate * glyph size
161 // * a few shapes have a height slightly bigger than 1.0 ( like '{' '[' )
162 point.x = (double) ( coordinate[0] - 'R' ) * STROKE_FONT_SCALE - glyphStartX;
163
164 // FONT_OFFSET is here for historical reasons, due to the way the stroke font
165 // was built. It allows shapes coordinates like W M ... to be >= 0
166 // Only shapes like j y have coordinates < 0
167 point.y = (double) ( coordinate[1] - 'R' + FONT_OFFSET ) * STROKE_FONT_SCALE;
168
169 glyph->AddPoint( point );
170 }
171
172 i += 2;
173 }
174
175 glyph->Finalize();
176
177 // Compute the bounding box of the glyph
178 buildGlyphBoundingBox( glyph, glyphWidth );
179 g_defaultFontGlyphBoundingBoxes->emplace_back( glyph->BoundingBox() );
180 g_defaultFontGlyphs.push_back( glyph );
181 m_maxGlyphWidth = std::max( m_maxGlyphWidth, glyphWidth );
182 }
183
185 }
186
190 m_fontFileName = wxEmptyString;
191}
192
193
194double STROKE_FONT::GetInterline( double aGlyphHeight, const METRICS& aFontMetrics ) const
195{
196 static double LEGACY_FACTOR = 0.9583; // Adjustment to match legacy spacing
197
198 return aFontMetrics.GetInterline( aGlyphHeight ) * LEGACY_FACTOR;
199}
200
201
202VECTOR2I STROKE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
203 const wxString& aText, const VECTOR2I& aSize,
204 const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
205 bool aMirror, const VECTOR2I& aOrigin,
206 TEXT_STYLE_FLAGS aTextStyle ) const
207{
208 constexpr int TAB_WIDTH = 4;
209 constexpr double INTER_CHAR = 0.2;
210 constexpr double SUPER_SUB_SIZE_MULTIPLIER = 0.8;
211 constexpr double SUPER_HEIGHT_OFFSET = 0.35;
212 constexpr double SUB_HEIGHT_OFFSET = 0.15;
213
214 VECTOR2I cursor( aPosition );
215 VECTOR2D glyphSize( aSize );
216 double tilt = ( aTextStyle & TEXT_STYLE::ITALIC ) ? ITALIC_TILT : 0.0;
217 double space_width = m_glyphBoundingBoxes->front().GetWidth(); // First char is space
218 int char_count = 0;
219
220 if( aTextStyle & TEXT_STYLE::SUBSCRIPT || aTextStyle & TEXT_STYLE::SUPERSCRIPT )
221 {
222 glyphSize = glyphSize * SUPER_SUB_SIZE_MULTIPLIER;
223
224 if( aTextStyle & TEXT_STYLE::SUBSCRIPT )
225 cursor.y += glyphSize.y * SUB_HEIGHT_OFFSET;
226 else
227 cursor.y -= glyphSize.y * SUPER_HEIGHT_OFFSET;
228 }
229
230 for( wxUniChar c : aText )
231 {
232 // Handle tabs as locked to the next 4th column (in base-widths).
233 if( c == '\t' )
234 {
235 char_count = ( char_count / TAB_WIDTH + 1 ) * TAB_WIDTH - 1;
236
237 int new_cursor = aPosition.x + aSize.x * char_count
238 + aSize.x * space_width;
239
240 while( new_cursor <= cursor.x )
241 {
242 char_count += TAB_WIDTH;
243 new_cursor += aSize.x * TAB_WIDTH;
244 }
245
246 cursor.x = new_cursor;
247 }
248 else if( c == ' ' )
249 {
250 // 'space' character - draw nothing, advance cursor position
251 cursor.x += KiROUND( glyphSize.x * space_width );
252 }
253 else
254 {
255 // dd is the index into bounding boxes table
256 int dd = (signed) c - ' ';
257
258 // Filtering non existing glyphs and non printable chars
259 if( dd < 0 || dd >= (int) m_glyphBoundingBoxes->size() )
260 {
261 c = '?';
262 dd = (signed) c - ' ';
263 }
264
265 STROKE_GLYPH* source = static_cast<STROKE_GLYPH*>( m_glyphs->at( dd ).get() );
266
267 if( aGlyphs )
268 {
269 aGlyphs->push_back( source->Transform( glyphSize, cursor, tilt, aAngle, aMirror,
270 aOrigin ) );
271 }
272
273 VECTOR2D glyphExtents = source->BoundingBox().GetEnd();
274
275 glyphExtents *= glyphSize;
276
277 cursor.x += KiROUND( glyphExtents.x );
278 }
279
280 ++char_count;
281 }
282
283 if( aBBox )
284 {
285 aBBox->SetOrigin( aPosition );
286 aBBox->SetEnd( cursor.x - KiROUND( glyphSize.x * INTER_CHAR ), cursor.y + glyphSize.y );
287 aBBox->Normalize();
288 }
289
290 return VECTOR2I( cursor.x, aPosition.y );
291}
BOX2< VECTOR2D > BOX2D
Definition: box2.h:854
void SetOrigin(const Vec &pos)
Definition: box2.h:203
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:120
const Vec GetEnd() const
Definition: box2.h:186
void SetEnd(coord_type x, coord_type y)
Definition: box2.h:256
wxString m_fontName
Font name.
Definition: font.h:276
wxString m_fontFileName
Font file name.
Definition: font.h:277
double GetInterline(double aFontHeight) const
Definition: font.h:114
Implement a stroke font drawing.
Definition: stroke_font.h:54
double GetInterline(double aGlyphHeight, const METRICS &aFontMetrics) const override
Compute the distance (interline) between 2 lines of text (for multiline texts).
void loadNewStrokeFont(const char *const aNewStrokeFont[], int aNewStrokeFontSize)
Load the standard KiCad stroke font.
Definition: stroke_font.cpp:99
const std::vector< BOX2D > * m_glyphBoundingBoxes
Definition: stroke_font.h:90
const std::vector< std::shared_ptr< GLYPH > > * m_glyphs
Definition: stroke_font.h:89
static STROKE_FONT * LoadFont(const wxString &aFontName)
Load a stroke font.
Definition: stroke_font.cpp:65
VECTOR2I GetTextAsGlyphs(BOX2I *aBoundingBox, std::vector< std::unique_ptr< GLYPH > > *aGlyphs, const wxString &aText, const VECTOR2I &aSize, const VECTOR2I &aPosition, const EDA_ANGLE &aAngle, bool aMirror, const VECTOR2I &aOrigin, TEXT_STYLE_FLAGS aTextStyle) const override
Convert text string to an array of GLYPHs.
BOX2D BoundingBox() override
Definition: glyph.h:116
std::unique_ptr< GLYPH > Transform(const VECTOR2D &aGlyphSize, const VECTOR2I &aOffset, double aTilt, const EDA_ANGLE &aAngle, bool aMirror, const VECTOR2I &aOrigin)
Definition: glyph.cpp:74
unsigned int TEXT_STYLE_FLAGS
Definition: font.h:64
static constexpr double ITALIC_TILT
Tilt factor for italic style (this is the scaling factor on dY relative coordinates to give a tilted ...
Definition: font.h:61
#define KICAD_FONT_NAME
const int newstroke_font_bufsize
const char *const newstroke_font[]
Modified 2019 to include based CJK Unicode Ideographs, using code copyright (c) 2018 Lingdong Huang.
static constexpr int FONT_OFFSET
Definition: stroke_font.cpp:48
std::mutex g_defaultFontLoadMutex
Definition: stroke_font.cpp:54
std::vector< std::shared_ptr< GLYPH > > g_defaultFontGlyphs
Definition: stroke_font.cpp:52
bool g_defaultFontInitialized
Definition: stroke_font.cpp:51
std::vector< BOX2D > * g_defaultFontGlyphBoundingBoxes
Definition: stroke_font.cpp:53
void buildGlyphBoundingBox(std::shared_ptr< STROKE_GLYPH > &aGlyph, double aGlyphWidth)
Definition: stroke_font.cpp:81
static constexpr double STROKE_FONT_SCALE
< Scale factor for a glyph
Definition: stroke_font.cpp:45
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588