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:
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
63 if( m_drcEngine->IsErrorLimitExceeded( DRCE_TEXT_HEIGHT )
64 && m_drcEngine->IsErrorLimitExceeded( DRCE_TEXT_THICKNESS ) )
65 {
66 REPORT_AUX( wxT( "Text dimension violations ignored. Tests not run." ) );
67 return true; // continue with other tests
68 }
69
70 if( !m_drcEngine->HasRulesForConstraintType( TEXT_HEIGHT_CONSTRAINT )
71 && !m_drcEngine->HasRulesForConstraintType( TEXT_THICKNESS_CONSTRAINT ) )
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 {
83 if( m_drcEngine->IsErrorLimitExceeded( DRCE_TEXT_HEIGHT ) )
84 return false;
85
86 DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( TEXT_HEIGHT_CONSTRAINT, item,
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 drcItem->SetErrorDetail( formatMsg( _( "(%s min height %s; actual %s)" ),
98 constraint.GetName(),
99 constraint.Value().Min(),
100 actualHeight ) );
101 drcItem->SetItems( item );
102 drcItem->SetViolatingRule( constraint.GetParentRule() );
103
104 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
105 }
106
107 if( constraint.Value().HasMax() && actualHeight > constraint.Value().Max() )
108 {
109 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_HEIGHT );
110 drcItem->SetErrorDetail( formatMsg( _( "(%s max height %s; actual %s)" ),
111 constraint.GetName(),
112 constraint.Value().Max(),
113 actualHeight ) );
114 drcItem->SetItems( item );
115 drcItem->SetViolatingRule( constraint.GetParentRule() );
116
117 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
118 }
119
120 return true;
121 };
122
123 auto checkTextThickness =
124 [&]( BOARD_ITEM* item, EDA_TEXT* text ) -> bool
125 {
126 DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( TEXT_THICKNESS_CONSTRAINT, item,
127 nullptr, item->GetLayer() );
128
129 if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE )
130 return true;
131
132 KIFONT::FONT* font = text->GetDrawFont( nullptr );
133
134 if( font->IsOutline() )
135 {
136 if( !constraint.Value().HasMin() || constraint.Value().Min() <= 0 )
137 return true;
138
139 auto* glyphs = text->GetRenderCache( font, text->GetShownText( true ) );
140 bool collapsedStroke = false;
141 bool collapsedArea = false;
142
143 for( const std::unique_ptr<KIFONT::GLYPH>& glyph : *glyphs )
144 {
145 // Ensure the glyph is a OUTLINE_GLYPH (for instance, overbars in outline
146 // font text are represented as STROKE_GLYPHs).
147 if( !glyph->IsOutline() )
148 continue;
149
150 auto outlineGlyph = static_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() );
151 int outlineCount = outlineGlyph->OutlineCount();
152 int holeCount = 0;
153
154 if( outlineCount == 0 )
155 continue; // ignore spaces
156
157 for( ii = 0; ii < outlineCount; ++ii )
158 holeCount += outlineGlyph->HoleCount( ii );
159
160 SHAPE_POLY_SET poly = outlineGlyph->CloneDropTriangulation();
161 poly.Deflate( constraint.Value().Min() / 2,
163 poly.Simplify();
164
165 int resultingOutlineCount = poly.OutlineCount();
166 int resultingHoleCount = 0;
167
168 for( ii = 0; ii < resultingOutlineCount; ++ii )
169 resultingHoleCount += poly.HoleCount( ii );
170
171 if( ( resultingOutlineCount != outlineCount )
172 || ( resultingHoleCount != holeCount ) )
173 {
174 collapsedStroke = true;
175 break;
176 }
177
178 double glyphArea = outlineGlyph->Area();
179
180 if( glyphArea == 0 )
181 continue;
182
183 poly.Inflate( constraint.Value().Min() / 2,
185
186 double resultingGlyphArea = poly.Area();
187
188 if( ( std::abs( resultingGlyphArea - glyphArea ) / glyphArea ) > 0.1 )
189 {
190 collapsedArea = true;
191 break;
192 }
193 }
194
195 if( collapsedStroke || collapsedArea )
196 {
197 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_THICKNESS );
198 drcItem->SetErrorDetail( _( "(TrueType font characters with insufficient stroke weight)" ) );
199 drcItem->SetItems( item );
200 drcItem->SetViolatingRule( constraint.GetParentRule() );
201
202 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
203 }
204 }
205 else
206 {
207 int actualThickness = text->GetEffectiveTextPenWidth();
208
209 if( constraint.Value().HasMin() && actualThickness < constraint.Value().Min() )
210 {
211 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_THICKNESS );
212 drcItem->SetErrorDetail( formatMsg( _( "(%s min thickness %s; actual %s)" ),
213 constraint.GetName(),
214 constraint.Value().Min(),
215 actualThickness ) );
216 drcItem->SetItems( item );
217 drcItem->SetViolatingRule( constraint.GetParentRule() );
218
219 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
220 }
221
222 if( constraint.Value().HasMax() && actualThickness > constraint.Value().Max() )
223 {
224 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_THICKNESS );
225 drcItem->SetErrorDetail( formatMsg( _( "(%s max thickness %s; actual %s)" ),
226 constraint.GetName(),
227 constraint.Value().Max(),
228 actualThickness ) );
229 drcItem->SetItems( item );
230 drcItem->SetViolatingRule( constraint.GetParentRule() );
231
232 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
233 }
234 }
235
236 return true;
237 };
238
239 static const std::vector<KICAD_T> itemTypes = {
243 };
244
246 [&]( BOARD_ITEM* item ) -> bool
247 {
248 ++count;
249 return true;
250 } );
251
253 [&]( BOARD_ITEM* item ) -> bool
254 {
255 if( !reportProgress( ii++, count, progressDelta ) )
256 return false;
257
258 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item ) )
259 {
260 int strikes = 0;
261
262 if( !text->IsVisible() )
263 return true;
264
265 if( m_drcEngine->IsErrorLimitExceeded( DRCE_TEXT_THICKNESS ) )
266 strikes++;
267 else
268 checkTextThickness( item, text );
269
270 if( m_drcEngine->IsErrorLimitExceeded( DRCE_TEXT_HEIGHT ) )
271 strikes++;
272 else
273 checkTextHeight( item, text );
274
275 if( strikes >= 2 )
276 return false;
277 }
278
279 return true;
280 } );
281
282 return !m_drcEngine->IsCancelled();
283}
284
285
286namespace detail
287{
289}
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:83
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:236
wxString GetName() const
Definition drc_rule.h:194
SEVERITY GetSeverity() const
Definition drc_rule.h:207
MINOPTMAX< int > & Value()
Definition drc_rule.h:187
DRC_RULE * GetParentRule() const
Definition drc_rule.h:190
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition drc_item.cpp:400
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:272
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
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
@ CHAMFER_ALL_CORNERS
All angles are chamfered.
@ DRCE_TEXT_HEIGHT
Definition drc_item.h:101
@ DRCE_TEXT_THICKNESS
Definition drc_item.h:102
@ 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