KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_test_provider.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 (C) 2020-2024 KiCad Developers, see AUTHORS.txt for contributors.
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 <drc/drc_engine.h>
25#include <drc/drc_item.h>
27#include <pcb_track.h>
28#include <footprint.h>
29#include <pad.h>
30#include <zone.h>
31#include <pcb_text.h>
32
33
34// A list of all basic (ie: non-compound) board geometry items
35std::vector<KICAD_T> DRC_TEST_PROVIDER::s_allBasicItems;
37
38
40{
41 for( DRC_TEST_PROVIDER* provider : m_providers )
42 delete provider;
43}
44
45
48 m_drcEngine( nullptr )
49{
50}
51
52
54{
55 if( s_allBasicItems.size() == 0 )
56 {
57 for( int i = 0; i < MAX_STRUCT_TYPE_ID; i++ )
58 {
59 if( i != PCB_FOOTPRINT_T && i != PCB_GROUP_T )
60 {
61 s_allBasicItems.push_back( (KICAD_T) i );
62
63 if( i != PCB_ZONE_T )
64 s_allBasicItemsButZones.push_back( (KICAD_T) i );
65 }
66 }
67 }
68}
69
70
71const wxString DRC_TEST_PROVIDER::GetName() const { return wxT( "<no name test>" ); }
72const wxString DRC_TEST_PROVIDER::GetDescription() const { return wxEmptyString; }
73
74
75void DRC_TEST_PROVIDER::reportViolation( std::shared_ptr<DRC_ITEM>& item,
76 const VECTOR2I& aMarkerPos, int aMarkerLayer )
77{
78 std::lock_guard<std::mutex> lock( m_statsMutex );
79 if( item->GetViolatingRule() )
80 accountCheck( item->GetViolatingRule() );
81
82 item->SetViolatingTest( this );
83 m_drcEngine->ReportViolation( item, aMarkerPos, aMarkerLayer );
84}
85
86
87bool DRC_TEST_PROVIDER::reportProgress( size_t aCount, size_t aSize, size_t aDelta )
88{
89 if( ( aCount % aDelta ) == 0 || aCount == aSize - 1 )
90 {
91 if( !m_drcEngine->ReportProgress( static_cast<double>( aCount ) / aSize ) )
92 return false;
93 }
94
95 return true;
96}
97
98
99bool DRC_TEST_PROVIDER::reportPhase( const wxString& aMessage )
100{
101 reportAux( aMessage );
102 return m_drcEngine->ReportPhase( aMessage );
103}
104
105
106void DRC_TEST_PROVIDER::reportAux( const wxChar* fmt, ... )
107{
108 va_list vargs;
109 va_start( vargs, fmt );
110 wxString str;
111 str.PrintfV( fmt, vargs );
112 va_end( vargs );
113 m_drcEngine->ReportAux( str );
114}
115
116
118{
119 auto it = m_stats.find( ruleToTest );
120
121 if( it == m_stats.end() )
122 m_stats[ ruleToTest ] = 1;
123 else
124 m_stats[ ruleToTest ] += 1;
125}
126
127
128void DRC_TEST_PROVIDER::accountCheck( const DRC_CONSTRAINT& constraintToTest )
129{
130 accountCheck( constraintToTest.GetParentRule() );
131}
132
133
135{
136 if( !m_isRuleDriven )
137 return;
138
139 m_drcEngine->ReportAux( wxT( "Rule hit statistics: " ) );
140
141 for( const std::pair<const DRC_RULE* const, int>& stat : m_stats )
142 {
143 if( stat.first )
144 {
145 m_drcEngine->ReportAux( wxString::Format( wxT( " - rule '%s': %d hits " ),
146 stat.first->m_Name,
147 stat.second ) );
148 }
149 }
150}
151
152
153int DRC_TEST_PROVIDER::forEachGeometryItem( const std::vector<KICAD_T>& aTypes, LSET aLayers,
154 const std::function<bool( BOARD_ITEM*)>& aFunc )
155{
156 BOARD *brd = m_drcEngine->GetBoard();
157 std::bitset<MAX_STRUCT_TYPE_ID> typeMask;
158 int n = 0;
159
160 if( aTypes.size() == 0 )
161 {
162 for( int i = 0; i < MAX_STRUCT_TYPE_ID; i++ )
163 typeMask[ i ] = true;
164 }
165 else
166 {
167 for( KICAD_T aType : aTypes )
168 typeMask[ aType ] = true;
169 }
170
171 for( PCB_TRACK* item : brd->Tracks() )
172 {
173 if( (item->GetLayerSet() & aLayers).any() )
174 {
175 if( typeMask[ PCB_TRACE_T ] && item->Type() == PCB_TRACE_T )
176 {
177 aFunc( item );
178 n++;
179 }
180 else if( typeMask[ PCB_VIA_T ] && item->Type() == PCB_VIA_T )
181 {
182 aFunc( item );
183 n++;
184 }
185 else if( typeMask[ PCB_ARC_T ] && item->Type() == PCB_ARC_T )
186 {
187 aFunc( item );
188 n++;
189 }
190 }
191 }
192
193 for( BOARD_ITEM* item : brd->Drawings() )
194 {
195 if( (item->GetLayerSet() & aLayers).any() )
196 {
197 if( typeMask[ PCB_DIMENSION_T ] && BaseType( item->Type() ) == PCB_DIMENSION_T )
198 {
199 if( !aFunc( item ) )
200 return n;
201
202 n++;
203 }
204 else if( typeMask[ PCB_SHAPE_T ] && item->Type() == PCB_SHAPE_T )
205 {
206 if( !aFunc( item ) )
207 return n;
208
209 n++;
210 }
211 else if( typeMask[ PCB_TEXT_T ] && item->Type() == PCB_TEXT_T )
212 {
213 if( !aFunc( item ) )
214 return n;
215
216 n++;
217 }
218 else if( typeMask[ PCB_TEXTBOX_T ] && item->Type() == PCB_TEXTBOX_T )
219 {
220 if( !aFunc( item ) )
221 return n;
222
223 n++;
224 }
225 else if( typeMask[ PCB_TARGET_T ] && item->Type() == PCB_TARGET_T )
226 {
227 if( !aFunc( item ) )
228 return n;
229
230 n++;
231 }
232 }
233 }
234
235 if( typeMask[ PCB_ZONE_T ] )
236 {
237 for( ZONE* item : brd->Zones() )
238 {
239 if( ( item->GetLayerSet() & aLayers ).any() )
240 {
241 if( !aFunc( item ) )
242 return n;
243
244 n++;
245 }
246 }
247 }
248
249 for( FOOTPRINT* footprint : brd->Footprints() )
250 {
251 if( typeMask[ PCB_FIELD_T ] )
252 {
253 for( PCB_FIELD* field : footprint->GetFields() )
254 {
255 if( ( field->GetLayerSet() & aLayers ).any() )
256 {
257 if( !aFunc( field ) )
258 return n;
259
260 n++;
261 }
262 }
263 }
264
265 if( typeMask[ PCB_PAD_T ] )
266 {
267 for( PAD* pad : footprint->Pads() )
268 {
269 // Careful: if a pad has a hole then it pierces all layers
270 if( pad->HasHole() || ( pad->GetLayerSet() & aLayers ).any() )
271 {
272 if( !aFunc( pad ) )
273 return n;
274
275 n++;
276 }
277 }
278 }
279
280 for( BOARD_ITEM* dwg : footprint->GraphicalItems() )
281 {
282 if( (dwg->GetLayerSet() & aLayers).any() )
283 {
284 if( typeMask[ PCB_DIMENSION_T ] && BaseType( dwg->Type() ) == PCB_DIMENSION_T )
285 {
286 if( !aFunc( dwg ) )
287 return n;
288
289 n++;
290 }
291 else if( typeMask[ PCB_TEXT_T ] && dwg->Type() == PCB_TEXT_T )
292 {
293 if( !aFunc( dwg ) )
294 return n;
295
296 n++;
297 }
298 else if( typeMask[ PCB_TEXTBOX_T ] && dwg->Type() == PCB_TEXTBOX_T )
299 {
300 if( !aFunc( dwg ) )
301 return n;
302
303 n++;
304 }
305 else if( typeMask[ PCB_SHAPE_T ] && dwg->Type() == PCB_SHAPE_T )
306 {
307 if( !aFunc( dwg ) )
308 return n;
309
310 n++;
311 }
312 }
313 }
314
315 if( typeMask[ PCB_ZONE_T ] )
316 {
317 for( ZONE* zone : footprint->Zones() )
318 {
319 if( (zone->GetLayerSet() & aLayers).any() )
320 {
321 if( !aFunc( zone ) )
322 return n;
323
324 n++;
325 }
326 }
327 }
328
329 if( typeMask[ PCB_FOOTPRINT_T ] )
330 {
331 if( !aFunc( footprint ) )
332 return n;
333
334 n++;
335 }
336 }
337
338 return n;
339}
340
341
343{
344 if( const PCB_TEXT* text = dynamic_cast<const PCB_TEXT*>( aItem ) )
345 {
346 if( !text->IsVisible() )
347 return true;
348 }
349
350 return false;
351}
352
353
354wxString DRC_TEST_PROVIDER::formatMsg( const wxString& aFormatString, const wxString& aSource,
355 double aConstraint, double aActual )
356{
357 wxString constraint_str = MessageTextFromValue( aConstraint );
358 wxString actual_str = MessageTextFromValue( aActual );
359
360 if( constraint_str == actual_str )
361 {
362 // Use more precise formatting if the message-text strings were equal.
363 constraint_str = StringFromValue( aConstraint, true );
364 actual_str = StringFromValue( aActual, true );
365 }
366
367 return wxString::Format( aFormatString, aSource, constraint_str, actual_str );
368}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:77
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:282
const ZONES & Zones() const
Definition: board.h:327
const FOOTPRINTS & Footprints() const
Definition: board.h:323
const TRACKS & Tracks() const
Definition: board.h:321
const DRAWINGS & Drawings() const
Definition: board.h:325
DRC_RULE * GetParentRule() const
Definition: drc_rule.h:145
BOARD * GetBoard() const
Definition: drc_engine.h:89
bool ReportProgress(double aProgress)
void ReportViolation(const std::shared_ptr< DRC_ITEM > &aItem, const VECTOR2I &aPos, int aMarkerLayer)
void ReportAux(const wxString &aStr)
bool ReportPhase(const wxString &aMessage)
std::vector< DRC_TEST_PROVIDER * > m_providers
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)
static std::vector< KICAD_T > s_allBasicItemsButZones
virtual bool reportPhase(const wxString &aStageName)
int forEachGeometryItem(const std::vector< KICAD_T > &aTypes, LSET aLayers, const std::function< bool(BOARD_ITEM *)> &aFunc)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer)
static std::vector< KICAD_T > s_allBasicItems
virtual const wxString GetDescription() const
DRC_ENGINE * m_drcEngine
bool isInvisibleText(const BOARD_ITEM *aItem) const
std::unordered_map< const DRC_RULE *, int > m_stats
void reportAux(const wxString &aMsg)
virtual void accountCheck(const DRC_RULE *ruleToTest)
virtual const wxString GetName() const
virtual void reportRuleStatistics()
virtual bool reportProgress(size_t aCount, size_t aSize, size_t aDelta=1)
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:575
Definition: pad.h:59
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
wxString StringFromValue(double aValue, bool aAddUnitLabel=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
Converts aValue in internal units into a united string.
Handle a list of polygons defining a copper zone.
Definition: zone.h:72
EDA_UNITS
Definition: eda_units.h:46
constexpr KICAD_T BaseType(const KICAD_T aType)
Return the underlying type of the given type.
Definition: typeinfo.h:248
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ MAX_STRUCT_TYPE_ID
Definition: typeinfo.h:236
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:110
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition: typeinfo.h:93
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:107
@ 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_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition: typeinfo.h:106
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition: typeinfo.h:100
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96