KiCad PCB EDA Suite
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-2021 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>
26 #include <drc/drc_test_provider.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
35 std::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 
47  m_drcEngine( nullptr )
48 {
49 }
50 
51 
52 const wxString DRC_TEST_PROVIDER::GetName() const { return "<no name test>"; }
53 const wxString DRC_TEST_PROVIDER::GetDescription() const { return ""; }
54 
55 
56 void DRC_TEST_PROVIDER::reportViolation( std::shared_ptr<DRC_ITEM>& item,
57  const wxPoint& aMarkerPos )
58 {
59  if( item->GetViolatingRule() )
60  accountCheck( item->GetViolatingRule() );
61 
62  item->SetViolatingTest( this );
63  m_drcEngine->ReportViolation( item, aMarkerPos );
64 }
65 
66 
67 bool DRC_TEST_PROVIDER::reportProgress( int aCount, int aSize, int aDelta )
68 {
69  if( ( aCount % aDelta ) == 0 || aCount == aSize - 1 )
70  {
71  if( !m_drcEngine->ReportProgress( (double) aCount / (double) aSize ) )
72  return false;
73  }
74 
75  return true;
76 }
77 
78 
79 bool DRC_TEST_PROVIDER::reportPhase( const wxString& aMessage )
80 {
81  reportAux( aMessage );
82  return m_drcEngine->ReportPhase( aMessage );
83 }
84 
85 
86 void DRC_TEST_PROVIDER::reportAux( wxString fmt, ... )
87 {
88  va_list vargs;
89  va_start( vargs, fmt );
90  wxString str;
91  str.PrintfV( fmt, vargs );
92  va_end( vargs );
93  m_drcEngine->ReportAux( str );
94 }
95 
96 
98 {
99  return m_drcEngine->UserUnits();
100 }
101 
102 
103 void DRC_TEST_PROVIDER::accountCheck( const DRC_RULE* ruleToTest )
104 {
105  auto it = m_stats.find( ruleToTest );
106 
107  if( it == m_stats.end() )
108  m_stats[ ruleToTest ] = 1;
109  else
110  m_stats[ ruleToTest ] += 1;
111 }
112 
113 
114 void DRC_TEST_PROVIDER::accountCheck( const DRC_CONSTRAINT& constraintToTest )
115 {
116  accountCheck( constraintToTest.GetParentRule() );
117 }
118 
119 
121 {
122  if( !m_isRuleDriven )
123  return;
124 
125  m_drcEngine->ReportAux( "Rule hit statistics: " );
126 
127  for( const std::pair<const DRC_RULE* const, int>& stat : m_stats )
128  {
129  if( stat.first )
130  {
131  m_drcEngine->ReportAux( wxString::Format( " - rule '%s': %d hits ",
132  stat.first->m_Name,
133  stat.second ) );
134  }
135  }
136 }
137 
138 
139 int DRC_TEST_PROVIDER::forEachGeometryItem( const std::vector<KICAD_T>& aTypes, LSET aLayers,
140  const std::function<bool( BOARD_ITEM*)>& aFunc )
141 {
142  BOARD *brd = m_drcEngine->GetBoard();
143  std::bitset<MAX_STRUCT_TYPE_ID> typeMask;
144  int n = 0;
145 
146  if( s_allBasicItems.size() == 0 )
147  {
148  for( int i = 0; i < MAX_STRUCT_TYPE_ID; i++ )
149  {
150  if( i != PCB_FOOTPRINT_T && i != PCB_GROUP_T )
151  {
152  s_allBasicItems.push_back( (KICAD_T) i );
153 
154  if( i != PCB_ZONE_T && i != PCB_FP_ZONE_T )
155  s_allBasicItemsButZones.push_back( (KICAD_T) i );
156  }
157  }
158  }
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_TARGET_T ] && item->Type() == PCB_TARGET_T )
219  {
220  if( !aFunc( item ) )
221  return n;
222 
223  n++;
224  }
225  }
226  }
227 
228  if( typeMask[ PCB_ZONE_T ] )
229  {
230  for( ZONE* item : brd->Zones() )
231  {
232  if( ( item->GetLayerSet() & aLayers ).any() )
233  {
234  if( !aFunc( item ) )
235  return n;
236 
237  n++;
238  }
239  }
240  }
241 
242  for( FOOTPRINT* footprint : brd->Footprints() )
243  {
244  if( typeMask[ PCB_FP_TEXT_T ] )
245  {
246  if( ( footprint->Reference().GetLayerSet() & aLayers ).any() )
247  {
248  if( !aFunc( &footprint->Reference() ) )
249  return n;
250 
251  n++;
252  }
253 
254  if( ( footprint->Value().GetLayerSet() & aLayers ).any() )
255  {
256  if( !aFunc( &footprint->Value() ) )
257  return n;
258 
259  n++;
260  }
261  }
262 
263  if( typeMask[ PCB_PAD_T ] )
264  {
265  for( PAD* pad : footprint->Pads() )
266  {
267  // Careful: if a pad has a hole then it pierces all layers
268  if( ( pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0 )
269  || ( pad->GetLayerSet() & aLayers ).any() )
270  {
271  if( !aFunc( pad ) )
272  return n;
273 
274  n++;
275  }
276  }
277  }
278 
279  for( BOARD_ITEM* dwg : footprint->GraphicalItems() )
280  {
281  if( (dwg->GetLayerSet() & aLayers).any() )
282  {
283  if( typeMask[ PCB_FP_TEXT_T ] && dwg->Type() == PCB_FP_TEXT_T )
284  {
285  if( !aFunc( dwg ) )
286  return n;
287 
288  n++;
289  }
290  else if( typeMask[ PCB_FP_SHAPE_T ] && dwg->Type() == PCB_FP_SHAPE_T )
291  {
292  if( !aFunc( dwg ) )
293  return n;
294 
295  n++;
296  }
297  }
298  }
299 
300  if( typeMask[ PCB_FP_ZONE_T ] )
301  {
302  for( ZONE* zone : footprint->Zones() )
303  {
304  if( (zone->GetLayerSet() & aLayers).any() )
305  {
306  if( !aFunc( zone ) )
307  return n;
308 
309  n++;
310  }
311  }
312  }
313 
314  if( typeMask[ PCB_FOOTPRINT_T ] )
315  {
316  if( !aFunc( footprint ) )
317  return n;
318 
319  n++;
320  }
321  }
322 
323  return n;
324 }
325 
326 
328 {
329 
330  if( const FP_TEXT* text = dyn_cast<const FP_TEXT*>( aItem ) )
331  {
332  if( !text->IsVisible() )
333  return true;
334  }
335 
336  if( const PCB_TEXT* text = dyn_cast<const PCB_TEXT*>( aItem ) )
337  {
338  if( !text->IsVisible() )
339  return true;
340  }
341 
342  return false;
343 }
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
ZONES & Zones()
Definition: board.h:240
bool ReportPhase(const wxString &aMessage)
bool isInvisibleText(const BOARD_ITEM *aItem) const
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:49
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:108
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const wxPoint &aMarkerPos)
std::vector< DRC_TEST_PROVIDER * > m_providers
constexpr KICAD_T BaseType(const KICAD_T aType)
Return the underlying type of the given type.
Definition: typeinfo.h:231
class PCB_TEXT, text on a layer
Definition: typeinfo.h:91
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:97
virtual bool reportProgress(int aCount, int aSize, int aDelta)
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:93
class PAD, a pad in a footprint
Definition: typeinfo.h:89
virtual const wxString GetName() const
virtual void reportRuleStatistics()
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:77
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
DRC_RULE * GetParentRule() const
Definition: drc_rule.h:126
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:505
BOARD * GetBoard() const
Definition: drc_engine.h:88
virtual bool reportPhase(const wxString &aStageName)
std::unordered_map< const DRC_RULE *, int > m_stats
FOOTPRINTS & Footprints()
Definition: board.h:234
bool ReportProgress(double aProgress)
virtual void accountCheck(const DRC_RULE *ruleToTest)
Handle a list of polygons defining a copper zone.
Definition: zone.h:56
class ZONE, a copper pour area
Definition: typeinfo.h:105
EDA_UNITS userUnits() const
virtual const wxString GetDescription() const
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition: typeinfo.h:99
class PCB_TARGET, a target (graphic item)
Definition: typeinfo.h:104
class FOOTPRINT, a footprint
Definition: typeinfo.h:88
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
EDA_UNITS
Definition: eda_units.h:38
int forEachGeometryItem(const std::vector< KICAD_T > &aTypes, LSET aLayers, const std::function< bool(BOARD_ITEM *)> &aFunc)
Represent a DRC "provider" which runs some DRC functions over a BOARD and spits out #DRC_ITEMs and po...
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:191
static std::vector< KICAD_T > s_allBasicItems
void ReportAux(const wxString &aStr)
static std::vector< KICAD_T > s_allBasicItemsButZones
DRC_ENGINE * m_drcEngine
class ZONE, managed by a footprint
Definition: typeinfo.h:94
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
EDA_UNITS UserUnits() const
Definition: drc_engine.h:155
Definition: pad.h:57
void ReportViolation(const std::shared_ptr< DRC_ITEM > &aItem, const wxPoint &aPos)
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:90
DRAWINGS & Drawings()
Definition: board.h:237
TRACKS & Tracks()
Definition: board.h:231
virtual void reportAux(wxString fmt,...)