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, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <macros.h>
21#include <pcb_field.h>
22#include <pcb_text.h>
23#include <pcb_textbox.h>
24#include <drc/drc_engine.h>
25#include <drc/drc_item.h>
26#include <drc/drc_rule.h>
28#include <font/font.h>
29#include <pcb_dimension.h>
30
31
32/*
33 Text dimensions tests.
34 Errors generated:
35 - DRCE_TEXT_HEIGHT
36 - DRCE_TEXT_THICKNESS
37*/
38
40{
41public:
44
45 virtual ~DRC_TEST_PROVIDER_TEXT_DIMS() = default;
46
47 virtual bool Run() override;
48
49 virtual const wxString GetName() const override { return wxT( "text_dimensions" ); };
50};
51
52
54{
55 const int progressDelta = 250;
56 int count = 0;
57 int ii = 0;
58
59 if( m_drcEngine->IsErrorLimitExceeded( DRCE_TEXT_HEIGHT )
60 && m_drcEngine->IsErrorLimitExceeded( DRCE_TEXT_THICKNESS ) )
61 {
62 REPORT_AUX( wxT( "Text dimension violations ignored. Tests not run." ) );
63 return true; // continue with other tests
64 }
65
66 if( !m_drcEngine->HasRulesForConstraintType( TEXT_HEIGHT_CONSTRAINT )
67 && !m_drcEngine->HasRulesForConstraintType( TEXT_THICKNESS_CONSTRAINT ) )
68 {
69 REPORT_AUX( wxT( "No text height or text thickness constraints found. Tests not run." ) );
70 return true; // continue with other tests
71 }
72
73 if( !reportPhase( _( "Checking text dimensions..." ) ) )
74 return false; // DRC cancelled
75
76 auto checkTextHeight =
77 [&]( BOARD_ITEM* item, EDA_TEXT* text ) -> bool
78 {
79 if( m_drcEngine->IsErrorLimitExceeded( DRCE_TEXT_HEIGHT ) )
80 return false;
81
82 DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( TEXT_HEIGHT_CONSTRAINT, item,
83 nullptr, item->GetLayer() );
84
85 if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE )
86 return true;
87
88 int actualHeight = text->GetTextSize().y;
89
90 if( constraint.Value().HasMin() && actualHeight < constraint.Value().Min() )
91 {
92 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_HEIGHT );
93 drcItem->SetErrorDetail( formatMsg( _( "(%s min height %s; actual %s)" ),
94 constraint.GetName(),
95 constraint.Value().Min(),
96 actualHeight ) );
97 drcItem->SetItems( item );
98 drcItem->SetViolatingRule( constraint.GetParentRule() );
99
100 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
101 }
102
103 if( constraint.Value().HasMax() && actualHeight > constraint.Value().Max() )
104 {
105 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_HEIGHT );
106 drcItem->SetErrorDetail( formatMsg( _( "(%s max height %s; actual %s)" ),
107 constraint.GetName(),
108 constraint.Value().Max(),
109 actualHeight ) );
110 drcItem->SetItems( item );
111 drcItem->SetViolatingRule( constraint.GetParentRule() );
112
113 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
114 }
115
116 return true;
117 };
118
119 auto checkTextThickness =
120 [&]( BOARD_ITEM* item, EDA_TEXT* text ) -> bool
121 {
122 DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( TEXT_THICKNESS_CONSTRAINT, item,
123 nullptr, item->GetLayer() );
124
125 if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE )
126 return true;
127
128 KIFONT::FONT* font = text->GetDrawFont( nullptr );
129
130 if( font->IsOutline() )
131 {
132 if( !constraint.Value().HasMin() || constraint.Value().Min() <= 0 )
133 return true;
134
135 auto* glyphs = text->GetRenderCache( font, text->GetShownText( true ) );
136 bool collapsedStroke = false;
137 bool collapsedArea = false;
138
139 for( const std::unique_ptr<KIFONT::GLYPH>& glyph : *glyphs )
140 {
141 // Ensure the glyph is a OUTLINE_GLYPH (for instance, overbars in outline
142 // font text are represented as STROKE_GLYPHs).
143 if( !glyph->IsOutline() )
144 continue;
145
146 auto outlineGlyph = static_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() );
147 int outlineCount = outlineGlyph->OutlineCount();
148 int holeCount = 0;
149
150 if( outlineCount == 0 )
151 continue; // ignore spaces
152
153 for( ii = 0; ii < outlineCount; ++ii )
154 holeCount += outlineGlyph->HoleCount( ii );
155
156 SHAPE_POLY_SET poly = outlineGlyph->CloneDropTriangulation();
157 poly.Deflate( constraint.Value().Min() / 2,
159 poly.Simplify();
160
161 int resultingOutlineCount = poly.OutlineCount();
162 int resultingHoleCount = 0;
163
164 for( ii = 0; ii < resultingOutlineCount; ++ii )
165 resultingHoleCount += poly.HoleCount( ii );
166
167 if( ( resultingOutlineCount != outlineCount )
168 || ( resultingHoleCount != holeCount ) )
169 {
170 collapsedStroke = true;
171 break;
172 }
173
174 double glyphArea = outlineGlyph->Area();
175
176 if( glyphArea == 0 )
177 continue;
178
179 poly.Inflate( constraint.Value().Min() / 2,
181
182 double resultingGlyphArea = poly.Area();
183
184 if( ( std::abs( resultingGlyphArea - glyphArea ) / glyphArea ) > 0.1 )
185 {
186 collapsedArea = true;
187 break;
188 }
189 }
190
191 if( collapsedStroke || collapsedArea )
192 {
193 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_THICKNESS );
194 drcItem->SetErrorDetail( _( "(TrueType font characters with insufficient stroke weight)" ) );
195 drcItem->SetItems( item );
196 drcItem->SetViolatingRule( constraint.GetParentRule() );
197
198 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
199 }
200 }
201 else
202 {
203 int actualThickness = text->GetEffectiveTextPenWidth();
204
205 if( constraint.Value().HasMin() && actualThickness < constraint.Value().Min() )
206 {
207 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_THICKNESS );
208 drcItem->SetErrorDetail( formatMsg( _( "(%s min thickness %s; actual %s)" ),
209 constraint.GetName(),
210 constraint.Value().Min(),
211 actualThickness ) );
212 drcItem->SetItems( item );
213 drcItem->SetViolatingRule( constraint.GetParentRule() );
214
215 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
216 }
217
218 if( constraint.Value().HasMax() && actualThickness > constraint.Value().Max() )
219 {
220 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_THICKNESS );
221 drcItem->SetErrorDetail( formatMsg( _( "(%s max thickness %s; actual %s)" ),
222 constraint.GetName(),
223 constraint.Value().Max(),
224 actualThickness ) );
225 drcItem->SetItems( item );
226 drcItem->SetViolatingRule( constraint.GetParentRule() );
227
228 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
229 }
230 }
231
232 return true;
233 };
234
235 static const std::vector<KICAD_T> itemTypes = {
239 };
240
242 [&]( BOARD_ITEM* item ) -> bool
243 {
244 ++count;
245 return true;
246 } );
247
249 [&]( BOARD_ITEM* item ) -> bool
250 {
251 if( !reportProgress( ii++, count, progressDelta ) )
252 return false;
253
254 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item ) )
255 {
256 int strikes = 0;
257
258 if( !text->IsVisible() )
259 return true;
260
261 if( m_drcEngine->IsErrorLimitExceeded( DRCE_TEXT_THICKNESS ) )
262 strikes++;
263 else
264 checkTextThickness( item, text );
265
266 if( m_drcEngine->IsErrorLimitExceeded( DRCE_TEXT_HEIGHT ) )
267 strikes++;
268 else
269 checkTextHeight( item, text );
270
271 if( strikes >= 2 )
272 return false;
273 }
274
275 return true;
276 } );
277
278 return !m_drcEngine->IsCancelled();
279}
280
281
282namespace detail
283{
285}
constexpr int ARC_LOW_DEF
Definition base_units.h:136
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:81
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:265
wxString GetName() const
Definition drc_rule.h:204
SEVERITY GetSeverity() const
Definition drc_rule.h:217
MINOPTMAX< int > & Value()
Definition drc_rule.h:197
DRC_RULE * GetParentRule() const
Definition drc_rule.h:200
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition drc_item.cpp:417
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
virtual bool reportPhase(const wxString &aStageName)
int forEachGeometryItem(const std::vector< KICAD_T > &aTypes, const LSET &aLayers, const std::function< bool(BOARD_ITEM *)> &aFunc)
void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer, const std::function< void(PCB_MARKER *)> &aPathGenerator=[](PCB_MARKER *){})
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:282
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:89
FONT is an abstract base class for both outline and stroke fonts.
Definition font.h:94
virtual bool IsOutline() const
Definition font.h:102
static const LSET & AllLayersMask()
Definition lset.cpp:637
T Min() const
Definition minoptmax.h:29
bool HasMax() const
Definition minoptmax.h:34
bool HasMin() const
Definition minoptmax.h:33
T Max() const
Definition minoptmax.h:30
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
@ CHAMFER_ALL_CORNERS
All angles are chamfered.
@ DRCE_TEXT_HEIGHT
Definition drc_item.h:98
@ DRCE_TEXT_THICKNESS
Definition drc_item.h:99
@ TEXT_THICKNESS_CONSTRAINT
Definition drc_rule.h:60
@ TEXT_HEIGHT_CONSTRAINT
Definition drc_rule.h:59
#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:86
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:85
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:83
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:88
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition typeinfo.h:93