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