KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
drc_test_provider_text_dims.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.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <macros.h>
25#include <pcb_field.h>
26#include <pcb_text.h>
27#include <pcb_textbox.h>
28#include <drc/drc_engine.h>
29#include <drc/drc_item.h>
30#include <drc/drc_rule.h>
32#include <font/font.h>
33#include <pcb_dimension.h>
34
35
36/*
37 Text dimensions tests.
38 Errors generated:
39 - DRCE_TEXT_HEIGHT
40 - DRCE_TEXT_THICKNESS
41*/
42
44{
45public:
47 {
48 }
49
51 {
52 }
53
54 virtual bool Run() override;
55
56 virtual const wxString GetName() const override
57 {
58 return wxT( "text_dimensions" );
59 };
60
61 virtual const wxString GetDescription() const override
62 {
63 return wxT( "Tests text height and thickness" );
64 }
65};
66
67
69{
70 const int progressDelta = 250;
71 int count = 0;
72 int ii = 0;
73
76 {
77 reportAux( wxT( "Text dimension violations ignored. Tests not run." ) );
78 return true; // continue with other tests
79 }
80
83 {
84 reportAux( wxT( "No text height or text thickness constraints found. Tests not run." ) );
85 return true; // continue with other tests
86 }
87
88 if( !reportPhase( _( "Checking text dimensions..." ) ) )
89 return false; // DRC cancelled
90
91 auto checkTextHeight =
92 [&]( BOARD_ITEM* item, EDA_TEXT* text ) -> bool
93 {
95 return false;
96
98 nullptr, item->GetLayer() );
99
100 if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE )
101 return true;
102
103 int actualHeight = text->GetTextSize().y;
104
105 if( constraint.Value().HasMin() && actualHeight < constraint.Value().Min() )
106 {
107 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_HEIGHT );
108 wxString msg = formatMsg( _( "(%s min height %s; actual %s)" ),
109 constraint.GetName(),
110 constraint.Value().Min(),
111 actualHeight );
112
113 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
114 drcItem->SetItems( item );
115 drcItem->SetViolatingRule( constraint.GetParentRule() );
116
117 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
118 }
119
120 if( constraint.Value().HasMax() && actualHeight > constraint.Value().Max() )
121 {
122 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_HEIGHT );
123 wxString msg = formatMsg( _( "(%s max height %s; actual %s)" ),
124 constraint.GetName(),
125 constraint.Value().Max(),
126 actualHeight );
127
128 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
129 drcItem->SetItems( item );
130 drcItem->SetViolatingRule( constraint.GetParentRule() );
131
132 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
133 }
134
135 return true;
136 };
137
138 auto checkTextThickness =
139 [&]( BOARD_ITEM* item, EDA_TEXT* text ) -> bool
140 {
142 nullptr, item->GetLayer() );
143
144 if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE )
145 return true;
146
147 KIFONT::FONT* font = text->GetFont();
148
149 if( !font )
150 font = KIFONT::FONT::GetFont( wxEmptyString, text->IsBold(), text->IsItalic() );
151
152 if( font->IsOutline() )
153 {
154 if( !constraint.Value().HasMin() || constraint.Value().Min() <= 0 )
155 return true;
156
157 auto* glyphs = text->GetRenderCache( font, text->GetShownText( true ) );
158 bool collapsedStroke = false;
159 bool collapsedArea = false;
160
161 for( const std::unique_ptr<KIFONT::GLYPH>& glyph : *glyphs )
162 {
163 // Ensure the glyph is a OUTLINE_GLYPH (for instance, overbars in outline
164 // font text are represented as STROKE_GLYPHs).
165 if( !glyph->IsOutline() )
166 continue;
167
168 auto outlineGlyph = static_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() );
169 int outlineCount = outlineGlyph->OutlineCount();
170 int holeCount = 0;
171
172 if( outlineCount == 0 )
173 continue; // ignore spaces
174
175 for( ii = 0; ii < outlineCount; ++ii )
176 holeCount += outlineGlyph->HoleCount( ii );
177
178 SHAPE_POLY_SET poly = outlineGlyph->CloneDropTriangulation();
179 poly.Deflate( constraint.Value().Min() / 2,
180 CORNER_STRATEGY::CHAMFER_ALL_CORNERS, ARC_LOW_DEF );
181 poly.Simplify();
182
183 int resultingOutlineCount = poly.OutlineCount();
184 int resultingHoleCount = 0;
185
186 for( ii = 0; ii < resultingOutlineCount; ++ii )
187 resultingHoleCount += poly.HoleCount( ii );
188
189 if( ( resultingOutlineCount != outlineCount )
190 || ( resultingHoleCount != holeCount ) )
191 {
192 collapsedStroke = true;
193 break;
194 }
195
196 double glyphArea = outlineGlyph->Area();
197
198 if( glyphArea == 0 )
199 continue;
200
201 poly.Inflate( constraint.Value().Min() / 2,
202 CORNER_STRATEGY::CHAMFER_ALL_CORNERS, ARC_LOW_DEF, true );
203
204 double resultingGlyphArea = poly.Area();
205
206 if( ( std::abs( resultingGlyphArea - glyphArea ) / glyphArea ) > 0.1 )
207 {
208 collapsedArea = true;
209 break;
210 }
211 }
212
213 if( collapsedStroke || collapsedArea )
214 {
215 auto drcItem = DRC_ITEM::Create( DRCE_TEXT_THICKNESS );
216 wxString msg;
217
218 msg = _( "(TrueType font characters with insufficient stroke weight)" );
219
220 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
221 drcItem->SetItems( item );
222 drcItem->SetViolatingRule( constraint.GetParentRule() );
223
224 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
225 }
226 }
227 else
228 {
229 int actualThickness = text->GetEffectiveTextPenWidth();
230
231 if( constraint.Value().HasMin() && actualThickness < constraint.Value().Min() )
232 {
233 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_THICKNESS );
234 wxString msg = formatMsg( _( "(%s min thickness %s; actual %s)" ),
235 constraint.GetName(),
236 constraint.Value().Min(),
237 actualThickness );
238
239 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
240 drcItem->SetItems( item );
241 drcItem->SetViolatingRule( constraint.GetParentRule() );
242
243 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
244 }
245
246 if( constraint.Value().HasMax() && actualThickness > constraint.Value().Max() )
247 {
248 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_THICKNESS );
249 wxString msg = formatMsg( _( "(%s max thickness %s; actual %s)" ),
250 constraint.GetName(),
251 constraint.Value().Max(),
252 actualThickness );
253
254 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
255 drcItem->SetItems( item );
256 drcItem->SetViolatingRule( constraint.GetParentRule() );
257
258 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
259 }
260 }
261
262 return true;
263 };
264
265 static const std::vector<KICAD_T> itemTypes = {
269 };
270
272 [&]( BOARD_ITEM* item ) -> bool
273 {
274 ++count;
275 return true;
276 } );
277
279 [&]( BOARD_ITEM* item ) -> bool
280 {
281 if( !reportProgress( ii++, count, progressDelta ) )
282 return false;
283
284 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item ) )
285 {
286 int strikes = 0;
287
288 if( !text->IsVisible() )
289 return true;
290
292 strikes++;
293 else
294 checkTextThickness( item, text );
295
297 strikes++;
298 else
299 checkTextHeight( item, text );
300
301 if( strikes >= 2 )
302 return false;
303 }
304
305 return true;
306 } );
307
309
310 return !m_drcEngine->IsCancelled();
311}
312
313
314namespace detail
315{
317}
constexpr int ARC_LOW_DEF
Definition: base_units.h:119
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:78
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:235
wxString GetName() const
Definition: drc_rule.h:160
SEVERITY GetSeverity() const
Definition: drc_rule.h:173
MINOPTMAX< int > & Value()
Definition: drc_rule.h:153
DRC_RULE * GetParentRule() const
Definition: drc_rule.h:156
bool HasRulesForConstraintType(DRC_CONSTRAINT_T constraintID)
bool IsErrorLimitExceeded(int error_code)
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
Definition: drc_engine.cpp:693
bool IsCancelled() const
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition: drc_item.cpp:393
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
virtual const wxString GetName() const override
virtual const wxString GetDescription() const override
Represent a DRC "provider" which runs some DRC functions over a BOARD and spits out DRC_ITEM and posi...
wxString formatMsg(const wxString &aFormatString, const wxString &aSource, double aConstraint, double aActual)
virtual bool reportPhase(const wxString &aStageName)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer, DRC_CUSTOM_MARKER_HANDLER *aCustomHandler=nullptr)
int forEachGeometryItem(const std::vector< KICAD_T > &aTypes, const LSET &aLayers, const std::function< bool(BOARD_ITEM *)> &aFunc)
DRC_ENGINE * m_drcEngine
void reportAux(const wxString &aMsg)
virtual void reportRuleStatistics()
virtual bool reportProgress(size_t aCount, size_t aSize, size_t aDelta=1)
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:248
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:80
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
virtual bool IsOutline() const
Definition: font.h:139
static LSET AllLayersMask()
Definition: lset.cpp:601
T Min() const
Definition: minoptmax.h:33
bool HasMax() const
Definition: minoptmax.h:38
bool HasMin() const
Definition: minoptmax.h:37
T Max() const
Definition: minoptmax.h:34
Represent a set of closed polygons.
double Area()
Return the area of this poly set.
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
void Deflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError)
int OutlineCount() const
Return the number of outlines in the set.
SHAPE_POLY_SET CloneDropTriangulation() const
@ DRCE_TEXT_HEIGHT
Definition: drc_item.h:99
@ DRCE_TEXT_THICKNESS
Definition: drc_item.h:100
@ TEXT_THICKNESS_CONSTRAINT
Definition: drc_rule.h:58
@ TEXT_HEIGHT_CONSTRAINT
Definition: drc_rule.h:57
#define _(s)
This file contains miscellaneous commonly used macros and functions.
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:390
@ RPT_SEVERITY_IGNORE
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition: typeinfo.h:93
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition: typeinfo.h:90
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition: typeinfo.h:95
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition: typeinfo.h:100