KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 virtual ~DRC_TEST_PROVIDER_TEXT_DIMS() = default;
50
51 virtual bool Run() override;
52
53 virtual const wxString GetName() const override { return wxT( "text_dimensions" ); };
54};
55
56
58{
59 const int progressDelta = 250;
60 int count = 0;
61 int ii = 0;
62
65 {
66 REPORT_AUX( wxT( "Text dimension violations ignored. Tests not run." ) );
67 return true; // continue with other tests
68 }
69
72 {
73 REPORT_AUX( wxT( "No text height or text thickness constraints found. Tests not run." ) );
74 return true; // continue with other tests
75 }
76
77 if( !reportPhase( _( "Checking text dimensions..." ) ) )
78 return false; // DRC cancelled
79
80 auto checkTextHeight =
81 [&]( BOARD_ITEM* item, EDA_TEXT* text ) -> bool
82 {
84 return false;
85
87 nullptr, item->GetLayer() );
88
89 if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE )
90 return true;
91
92 int actualHeight = text->GetTextSize().y;
93
94 if( constraint.Value().HasMin() && actualHeight < constraint.Value().Min() )
95 {
96 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_HEIGHT );
97 wxString msg = formatMsg( _( "(%s min height %s; actual %s)" ),
98 constraint.GetName(),
99 constraint.Value().Min(),
100 actualHeight );
101
102 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
103 drcItem->SetItems( item );
104 drcItem->SetViolatingRule( constraint.GetParentRule() );
105
106 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
107 }
108
109 if( constraint.Value().HasMax() && actualHeight > constraint.Value().Max() )
110 {
111 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_HEIGHT );
112 wxString msg = formatMsg( _( "(%s max height %s; actual %s)" ),
113 constraint.GetName(),
114 constraint.Value().Max(),
115 actualHeight );
116
117 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
118 drcItem->SetItems( item );
119 drcItem->SetViolatingRule( constraint.GetParentRule() );
120
121 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
122 }
123
124 return true;
125 };
126
127 auto checkTextThickness =
128 [&]( BOARD_ITEM* item, EDA_TEXT* text ) -> bool
129 {
131 nullptr, item->GetLayer() );
132
133 if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE )
134 return true;
135
136 KIFONT::FONT* font = text->GetDrawFont( nullptr );
137
138 if( font->IsOutline() )
139 {
140 if( !constraint.Value().HasMin() || constraint.Value().Min() <= 0 )
141 return true;
142
143 auto* glyphs = text->GetRenderCache( font, text->GetShownText( true ) );
144 bool collapsedStroke = false;
145 bool collapsedArea = false;
146
147 for( const std::unique_ptr<KIFONT::GLYPH>& glyph : *glyphs )
148 {
149 // Ensure the glyph is a OUTLINE_GLYPH (for instance, overbars in outline
150 // font text are represented as STROKE_GLYPHs).
151 if( !glyph->IsOutline() )
152 continue;
153
154 auto outlineGlyph = static_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() );
155 int outlineCount = outlineGlyph->OutlineCount();
156 int holeCount = 0;
157
158 if( outlineCount == 0 )
159 continue; // ignore spaces
160
161 for( ii = 0; ii < outlineCount; ++ii )
162 holeCount += outlineGlyph->HoleCount( ii );
163
164 SHAPE_POLY_SET poly = outlineGlyph->CloneDropTriangulation();
165 poly.Deflate( constraint.Value().Min() / 2,
166 CORNER_STRATEGY::CHAMFER_ALL_CORNERS, ARC_LOW_DEF );
167 poly.Simplify();
168
169 int resultingOutlineCount = poly.OutlineCount();
170 int resultingHoleCount = 0;
171
172 for( ii = 0; ii < resultingOutlineCount; ++ii )
173 resultingHoleCount += poly.HoleCount( ii );
174
175 if( ( resultingOutlineCount != outlineCount )
176 || ( resultingHoleCount != holeCount ) )
177 {
178 collapsedStroke = true;
179 break;
180 }
181
182 double glyphArea = outlineGlyph->Area();
183
184 if( glyphArea == 0 )
185 continue;
186
187 poly.Inflate( constraint.Value().Min() / 2,
188 CORNER_STRATEGY::CHAMFER_ALL_CORNERS, ARC_LOW_DEF, true );
189
190 double resultingGlyphArea = poly.Area();
191
192 if( ( std::abs( resultingGlyphArea - glyphArea ) / glyphArea ) > 0.1 )
193 {
194 collapsedArea = true;
195 break;
196 }
197 }
198
199 if( collapsedStroke || collapsedArea )
200 {
201 auto drcItem = DRC_ITEM::Create( DRCE_TEXT_THICKNESS );
202 wxString msg;
203
204 msg = _( "(TrueType font characters with insufficient stroke weight)" );
205
206 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
207 drcItem->SetItems( item );
208 drcItem->SetViolatingRule( constraint.GetParentRule() );
209
210 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
211 }
212 }
213 else
214 {
215 int actualThickness = text->GetEffectiveTextPenWidth();
216
217 if( constraint.Value().HasMin() && actualThickness < constraint.Value().Min() )
218 {
219 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_THICKNESS );
220 wxString msg = formatMsg( _( "(%s min thickness %s; actual %s)" ),
221 constraint.GetName(),
222 constraint.Value().Min(),
223 actualThickness );
224
225 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
226 drcItem->SetItems( item );
227 drcItem->SetViolatingRule( constraint.GetParentRule() );
228
229 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
230 }
231
232 if( constraint.Value().HasMax() && actualThickness > constraint.Value().Max() )
233 {
234 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_THICKNESS );
235 wxString msg = formatMsg( _( "(%s max thickness %s; actual %s)" ),
236 constraint.GetName(),
237 constraint.Value().Max(),
238 actualThickness );
239
240 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
241 drcItem->SetItems( item );
242 drcItem->SetViolatingRule( constraint.GetParentRule() );
243
244 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
245 }
246 }
247
248 return true;
249 };
250
251 static const std::vector<KICAD_T> itemTypes = {
255 };
256
258 [&]( BOARD_ITEM* item ) -> bool
259 {
260 ++count;
261 return true;
262 } );
263
265 [&]( BOARD_ITEM* item ) -> bool
266 {
267 if( !reportProgress( ii++, count, progressDelta ) )
268 return false;
269
270 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item ) )
271 {
272 int strikes = 0;
273
274 if( !text->IsVisible() )
275 return true;
276
278 strikes++;
279 else
280 checkTextThickness( item, text );
281
283 strikes++;
284 else
285 checkTextHeight( item, text );
286
287 if( strikes >= 2 )
288 return false;
289 }
290
291 return true;
292 } );
293
294 return !m_drcEngine->IsCancelled();
295}
296
297
298namespace detail
299{
301}
constexpr int ARC_LOW_DEF
Definition: base_units.h:128
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:232
wxString GetName() const
Definition: drc_rule.h:168
SEVERITY GetSeverity() const
Definition: drc_rule.h:181
MINOPTMAX< int > & Value()
Definition: drc_rule.h:161
DRC_RULE * GetParentRule() const
Definition: drc_rule.h:164
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:706
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 ~DRC_TEST_PROVIDER_TEXT_DIMS()=default
virtual const wxString GetName() const override
Represent a DRC "provider" which runs some DRC functions over a BOARD and spits out DRC_ITEM and posi...
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
wxString formatMsg(const wxString &aFormatString, const wxString &aSource, double aConstraint, double aActual, EDA_DATA_TYPE aDataType=EDA_DATA_TYPE::DISTANCE)
virtual bool reportProgress(size_t aCount, size_t aSize, size_t aDelta=1)
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:272
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:79
FONT is an abstract base class for both outline and stroke fonts.
Definition: font.h:131
virtual bool IsOutline() const
Definition: font.h:139
static const LSET & AllLayersMask()
Definition: lset.cpp:624
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 REPORT_AUX(s)
#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:400
@ 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