KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_label_bounding_box.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
21
22#include <sch_label.h>
23#include <sch_text.h>
24#include <font/font.h>
25#include <font/outline_font.h>
26#include <font/stroke_font.h>
28
29
34{
36 {
37 }
38
40 {
41 const std::vector<wxString> fontNames = {
42 wxS( "Arial" ),
43 wxS( "Segoe UI" ),
44 wxS( "Tahoma" ),
45 wxS( "Verdana" ),
46 wxS( "DejaVu Sans" ),
47 wxS( "Liberation Sans" ),
48 wxS( "FreeSans" ),
49 wxS( "Ubuntu" ),
50 wxS( "Helvetica" ),
51 wxS( "Helvetica Neue" )
52 };
53
54 for( const wxString& name : fontNames )
55 {
56 KIFONT::FONT* font = KIFONT::FONT::GetFont( name, false, false );
57
58 if( font && font->IsOutline() )
59 return font;
60 }
61
62 return nullptr;
63 }
64
71 void CheckTextBoundingBoxWidth( const EDA_TEXT& aText, const wxString& aTestName,
72 double aMaxWidthMultiplier = 1.3 )
73 {
74 KIFONT::FONT* font = aText.GetDrawFont( nullptr );
75 BOOST_REQUIRE_MESSAGE( font, aTestName + ": Font should not be null" );
76
77 VECTOR2I textSize = aText.GetTextSize();
78 int thickness = aText.GetEffectiveTextPenWidth();
79 wxString text = aText.GetShownText( true );
80
81 // Get the text width from the font using empty metrics (defaults)
82 KIFONT::METRICS metrics;
83 VECTOR2I extents = font->StringBoundaryLimits( text, textSize, thickness,
84 aText.IsBold(), aText.IsItalic(),
85 metrics );
86
87 // Get the actual bounding box
88 BOX2I bbox = aText.GetTextBox( nullptr );
89
90 // The bounding box width should be close to the text extents width
91 // Allow some margin for font metrics, pen width, etc.
92 int expectedMaxWidth = extents.x * aMaxWidthMultiplier;
93
94 BOOST_TEST_MESSAGE( aTestName + ": Font: " + font->GetName() );
95 BOOST_TEST_MESSAGE( " Text: '" + text + "'" );
96 BOOST_TEST_MESSAGE( " Text extents width: " + std::to_string( extents.x ) );
97 BOOST_TEST_MESSAGE( " BBox width: " + std::to_string( bbox.GetWidth() ) );
98 BOOST_TEST_MESSAGE( " Expected max width: " + std::to_string( expectedMaxWidth ) );
99
100 // Check that bbox is not excessively wide (like double the text width)
101 BOOST_CHECK_MESSAGE( bbox.GetWidth() <= expectedMaxWidth,
102 aTestName + ": Bounding box width (" + std::to_string( bbox.GetWidth() )
103 + ") exceeds expected max (" + std::to_string( expectedMaxWidth )
104 + "). Text may have been measured twice." );
105
106 // Also check that the bbox is not too small (sanity check)
107 int expectedMinWidth = extents.x * 0.7;
108 BOOST_CHECK_MESSAGE( bbox.GetWidth() >= expectedMinWidth,
109 aTestName + ": Bounding box width (" + std::to_string( bbox.GetWidth() )
110 + ") is smaller than expected min (" + std::to_string( expectedMinWidth ) + ")" );
111 }
112
116 void CheckLabelBodyBoundingBox( SCH_LABEL_BASE& aLabel, const wxString& aTestName )
117 {
118 BOX2I bodyBBox = aLabel.GetBodyBoundingBox( nullptr );
119 BOX2I textBBox = aLabel.GetTextBox( nullptr );
120
121 BOOST_TEST_MESSAGE( aTestName + ": Label body bbox width: " + std::to_string( bodyBBox.GetWidth() ) );
122 BOOST_TEST_MESSAGE( " Label text bbox width: " + std::to_string( textBBox.GetWidth() ) );
123
124 // Body bbox should be at least as wide as text bbox (may include margins)
125 BOOST_CHECK_MESSAGE( bodyBBox.GetWidth() >= textBBox.GetWidth(),
126 aTestName + ": Body bbox width (" + std::to_string( bodyBBox.GetWidth() )
127 + ") should be >= text bbox width (" + std::to_string( textBBox.GetWidth() ) + ")" );
128
129 // Body bbox should not be excessively larger than text bbox
130 // Allow up to 3x for labels with shapes (global labels, etc.)
131 int maxBodyWidth = textBBox.GetWidth() * 3;
132 BOOST_CHECK_MESSAGE( bodyBBox.GetWidth() <= maxBodyWidth,
133 aTestName + ": Body bbox width (" + std::to_string( bodyBBox.GetWidth() )
134 + ") is excessively large compared to text bbox width ("
135 + std::to_string( textBBox.GetWidth() ) + ")" );
136 }
137};
138
139
140BOOST_FIXTURE_TEST_SUITE( LabelBoundingBox, LABEL_BBOX_FIXTURE )
141
142
143
146BOOST_AUTO_TEST_CASE( TextBoundingBoxStrokeFont )
147{
148 SCH_TEXT text( VECTOR2I( 0, 0 ), wxS( "TEST_TEXT" ) );
149 text.SetTextSize( VECTOR2I( 1000, 1000 ) );
150
151 // Use default KiCad font (stroke font)
152 text.SetFont( nullptr );
153
154 CheckTextBoundingBoxWidth( text, "SCH_TEXT with stroke font" );
155}
156
157
161BOOST_AUTO_TEST_CASE( TextBoundingBoxOutlineFont )
162{
163 SCH_TEXT text( VECTOR2I( 0, 0 ), wxS( "TEST_TEXT" ) );
164 text.SetTextSize( VECTOR2I( 1000, 1000 ) );
165
166 // Try to load an outline font - use a common system font
167 // If not available, the test will skip
168 KIFONT::FONT* font = GetFirstExistingOutlineFont();
169
170 if( !font )
171 {
172 BOOST_TEST_MESSAGE( "Outline font not available, skipping test" );
173 return;
174 }
175
176 text.SetFont( font );
177
178 CheckTextBoundingBoxWidth( text, "SCH_TEXT with outline font (" + font->GetName() + ")" );
179}
180
181
185BOOST_AUTO_TEST_CASE( TextBoundingBoxVariousStrings )
186{
187 std::vector<wxString> testStrings = {
188 wxS( "A" ),
189 wxS( "ABC" ),
190 wxS( "TEST" ),
191 wxS( "Hello World" ),
192 wxS( "1234567890" ),
193 wxS( "WWWWW" ), // Wide characters
194 wxS( "iiiii" ), // Narrow characters
195 };
196
197 // Test with stroke font
198 for( const wxString& str : testStrings )
199 {
200 SCH_TEXT text( VECTOR2I( 0, 0 ), str );
201 text.SetTextSize( VECTOR2I( 1000, 1000 ) );
202 text.SetFont( nullptr ); // KiCad stroke font
203
204 CheckTextBoundingBoxWidth( text, "Stroke font: '" + str + "'" );
205 }
206
207 // Test with outline font if available
208 KIFONT::FONT* font = GetFirstExistingOutlineFont();
209
210 if( font )
211 {
212 for( const wxString& str : testStrings )
213 {
214 SCH_TEXT text( VECTOR2I( 0, 0 ), str );
215 text.SetTextSize( VECTOR2I( 1000, 1000 ) );
216 text.SetFont( font );
217
218 CheckTextBoundingBoxWidth( text, "Outline font: '" + str + "'" );
219 }
220 }
221}
222
223
227BOOST_AUTO_TEST_CASE( LabelBodyBoundingBoxStrokeFont )
228{
229 SCH_LABEL label( VECTOR2I( 0, 0 ), wxS( "TEST_LABEL" ) );
230 label.SetTextSize( VECTOR2I( 1000, 1000 ) );
231 label.SetFont( nullptr ); // KiCad stroke font
232
233 CheckTextBoundingBoxWidth( label, "SCH_LABEL text with stroke font" );
234 CheckLabelBodyBoundingBox( label, "SCH_LABEL body with stroke font" );
235}
236
237
241BOOST_AUTO_TEST_CASE( LabelBodyBoundingBoxOutlineFont )
242{
243 KIFONT::FONT* font = GetFirstExistingOutlineFont();
244
245 if( !font )
246 {
247 BOOST_TEST_MESSAGE( "Outline font not available, skipping test" );
248 return;
249 }
250
251 SCH_LABEL label( VECTOR2I( 0, 0 ), wxS( "TEST_LABEL" ) );
252 label.SetTextSize( VECTOR2I( 1000, 1000 ) );
253 label.SetFont( font );
254
255 CheckTextBoundingBoxWidth( label, "SCH_LABEL text with outline font" );
256 CheckLabelBodyBoundingBox( label, "SCH_LABEL body with outline font" );
257}
258
259
263BOOST_AUTO_TEST_CASE( GlobalLabelBodyBoundingBoxStrokeFont )
264{
265 SCH_GLOBALLABEL label( VECTOR2I( 0, 0 ), wxS( "GLOBAL_TEST" ) );
266 label.SetTextSize( VECTOR2I( 1000, 1000 ) );
267 label.SetFont( nullptr ); // KiCad stroke font
268
269 CheckTextBoundingBoxWidth( label, "SCH_GLOBALLABEL text with stroke font" );
270 CheckLabelBodyBoundingBox( label, "SCH_GLOBALLABEL body with stroke font" );
271}
272
273
278BOOST_AUTO_TEST_CASE( GlobalLabelBodyBoundingBoxOutlineFont )
279{
280 KIFONT::FONT* font = GetFirstExistingOutlineFont();
281
282 if( !font )
283 {
284 BOOST_TEST_MESSAGE( "Outline font not available, skipping test" );
285 return;
286 }
287
288 SCH_GLOBALLABEL label( VECTOR2I( 0, 0 ), wxS( "GLOBAL_TEST" ) );
289 label.SetTextSize( VECTOR2I( 1000, 1000 ) );
290 label.SetFont( font );
291
292 CheckTextBoundingBoxWidth( label, "SCH_GLOBALLABEL text with outline font" );
293 CheckLabelBodyBoundingBox( label, "SCH_GLOBALLABEL body with outline font" );
294}
295
296
300BOOST_AUTO_TEST_CASE( HierLabelBodyBoundingBoxStrokeFont )
301{
302 SCH_HIERLABEL label( VECTOR2I( 0, 0 ), wxS( "HIER_TEST" ) );
303 label.SetTextSize( VECTOR2I( 1000, 1000 ) );
304 label.SetFont( nullptr ); // KiCad stroke font
305
306 CheckTextBoundingBoxWidth( label, "SCH_HIERLABEL text with stroke font" );
307 CheckLabelBodyBoundingBox( label, "SCH_HIERLABEL body with stroke font" );
308}
309
310
314BOOST_AUTO_TEST_CASE( HierLabelBodyBoundingBoxOutlineFont )
315{
316 KIFONT::FONT* font = GetFirstExistingOutlineFont();
317
318 if( !font )
319 {
320 BOOST_TEST_MESSAGE( "Outline font not available, skipping test" );
321 return;
322 }
323
324 SCH_HIERLABEL label( VECTOR2I( 0, 0 ), wxS( "HIER_TEST" ) );
325 label.SetTextSize( VECTOR2I( 1000, 1000 ) );
326 label.SetFont( font );
327
328 CheckTextBoundingBoxWidth( label, "SCH_HIERLABEL text with outline font" );
329 CheckLabelBodyBoundingBox( label, "SCH_HIERLABEL body with outline font" );
330}
331
332
const char * name
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr size_type GetWidth() const
Definition box2.h:214
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:80
bool IsItalic() const
Definition eda_text.h:169
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition eda_text.cpp:541
BOX2I GetTextBox(const RENDER_SETTINGS *aSettings, int aLine=-1) const
Useful in multiline texts to calculate the full text or a line area (for zones filling,...
Definition eda_text.cpp:746
virtual KIFONT::FONT * GetDrawFont(const RENDER_SETTINGS *aSettings) const
Definition eda_text.cpp:656
int GetEffectiveTextPenWidth(int aDefaultPenWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultPenWidth.
Definition eda_text.cpp:474
bool IsBold() const
Definition eda_text.h:184
virtual wxString GetShownText(bool aAllowExtraText, int aDepth=0) const
Return the string actually shown after processing of the base text.
Definition eda_text.h:109
void SetFont(KIFONT::FONT *aFont)
Definition eda_text.cpp:508
VECTOR2I GetTextSize() const
Definition eda_text.h:261
FONT is an abstract base class for both outline and stroke fonts.
Definition font.h:131
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
Definition font.cpp:147
const wxString & GetName() const
Definition font.h:149
virtual bool IsOutline() const
Definition font.h:139
VECTOR2I StringBoundaryLimits(const wxString &aText, const VECTOR2I &aSize, int aThickness, bool aBold, bool aItalic, const METRICS &aFontMetrics) const
Compute the boundary limits of aText (the bounding box of all shapes).
Definition font.cpp:451
virtual const BOX2I GetBodyBoundingBox(const RENDER_SETTINGS *aSettings) const
Return the bounding box of the label only, without taking in account its fields.
Test fixture for label bounding box tests.
KIFONT::FONT * GetFirstExistingOutlineFont()
void CheckLabelBodyBoundingBox(SCH_LABEL_BASE &aLabel, const wxString &aTestName)
Helper function to check label body bounding box.
void CheckTextBoundingBoxWidth(const EDA_TEXT &aText, const wxString &aTestName, double aMaxWidthMultiplier=1.3)
Helper function to check that a text bounding box is reasonable.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(TextBoundingBoxStrokeFont)
Test that SCH_TEXT bounding boxes are correct with the default KiCad font (stroke font).
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695