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 The 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, see <https://www.gnu.org/licenses/>.
18 */
19
20#include "pcb_table.h"
21#include <drc/drc_item.h>
23#include <pcb_track.h>
24#include <footprint.h>
25#include <pad.h>
26#include <zone.h>
27#include <pcb_text.h>
28#include <properties/property.h>
30
31
32// A list of all basic (ie: non-compound) board geometry items
33std::vector<KICAD_T> DRC_TEST_PROVIDER::s_allBasicItems;
35
36
42
43
49
50
57
58
60{
61 if( s_allBasicItems.size() == 0 )
62 {
63 for( int i = 0; i < MAX_STRUCT_TYPE_ID; i++ )
64 {
65 if( i != PCB_FOOTPRINT_T && i != PCB_GROUP_T )
66 {
67 s_allBasicItems.push_back( (KICAD_T) i );
68
69 if( i != PCB_ZONE_T )
70 s_allBasicItemsButZones.push_back( (KICAD_T) i );
71 }
72 }
73 }
74}
75
76
77const wxString DRC_TEST_PROVIDER::GetName() const { return wxT( "<no name test>" ); }
78
79
80void DRC_TEST_PROVIDER::reportViolation( std::shared_ptr<DRC_ITEM>& item,
81 const VECTOR2I& aMarkerPos, int aMarkerLayer,
82 const std::function<void( PCB_MARKER* )>& aPathGenerator )
83{
84 item->SetViolatingTest( this );
85 m_drcEngine->ReportViolation( item, aMarkerPos, aMarkerLayer, aPathGenerator );
86}
87
88
89void DRC_TEST_PROVIDER::reportTwoPointGeometry( std::shared_ptr<DRC_ITEM>& aDrcItem, const VECTOR2I& aMarkerPos,
90 const VECTOR2I& ptA, const VECTOR2I& ptB, PCB_LAYER_ID aLayer )
91{
92 PCB_SHAPE ptAShape( nullptr, SHAPE_T::SEGMENT );
93 ptAShape.SetStart( ptA );
94 ptAShape.SetEnd( ptB );
95
96 reportViolation( aDrcItem, aMarkerPos, aLayer,
97 [&]( PCB_MARKER* aMarker )
98 {
99 aMarker->SetPath( { ptAShape }, ptA, ptB );
100 } );
101}
102
103
104void DRC_TEST_PROVIDER::reportTwoShapeGeometry( std::shared_ptr<DRC_ITEM>& aDrcItem, const VECTOR2I& aMarkerPos,
105 const SHAPE* aShape1, const SHAPE* aShape2, PCB_LAYER_ID aLayer,
106 int aDistance )
107{
108 VECTOR2I ptA, ptB;
109
110 if( aDistance == 0 )
111 {
112 reportTwoPointGeometry( aDrcItem, aMarkerPos, aMarkerPos, aMarkerPos, aLayer );
113 }
114 else if( aShape1->NearestPoints( aShape2, ptA, ptB ) )
115 {
116 reportTwoPointGeometry( aDrcItem, aMarkerPos, ptA, ptB, aLayer );
117 }
118 else
119 {
120 reportViolation( aDrcItem, aMarkerPos, aLayer );
121 }
122}
123
124
125void DRC_TEST_PROVIDER::reportTwoItemGeometry( std::shared_ptr<DRC_ITEM>& aDrcItem, const VECTOR2I& aMarkerPos,
126 const BOARD_ITEM* aItem1, const BOARD_ITEM* aItem2,
127 PCB_LAYER_ID aLayer, int aDistance )
128{
129 std::shared_ptr<SHAPE> aShape1 = aItem1->GetEffectiveShape( aLayer );
130 std::shared_ptr<SHAPE> aShape2 = aItem2->GetEffectiveShape( aLayer );
131
132 reportTwoShapeGeometry( aDrcItem, aMarkerPos, aShape1.get(), aShape2.get(), aLayer, aDistance );
133}
134
135
136bool DRC_TEST_PROVIDER::reportProgress( size_t aCount, size_t aSize, size_t aDelta )
137{
138 if( ( aCount % aDelta ) == 0 || aCount == aSize - 1 )
139 {
140 if( !m_drcEngine->ReportProgress( static_cast<double>( aCount ) / aSize ) )
141 return false;
142 }
143
144 return true;
145}
146
147
148bool DRC_TEST_PROVIDER::reportPhase( const wxString& aMessage )
149{
150 REPORT_AUX( aMessage );
151 return m_drcEngine->ReportPhase( aMessage );
152}
153
154
155int DRC_TEST_PROVIDER::forEachGeometryItem( const std::vector<KICAD_T>& aTypes, const LSET& aLayers,
156 const std::function<bool( BOARD_ITEM*)>& aFunc )
157{
158 BOARD *brd = m_drcEngine->GetBoard();
159 std::bitset<MAX_STRUCT_TYPE_ID> typeMask;
160 int n = 0;
161
162 if( aTypes.size() == 0 )
163 {
164 for( int i = 0; i < MAX_STRUCT_TYPE_ID; i++ )
165 typeMask[ i ] = true;
166 }
167 else
168 {
169 for( KICAD_T aType : aTypes )
170 typeMask[ aType ] = true;
171 }
172
173 for( PCB_TRACK* item : brd->Tracks() )
174 {
175 if( (item->GetLayerSet() & aLayers).any() )
176 {
177 if( typeMask[ PCB_TRACE_T ] && item->Type() == PCB_TRACE_T )
178 {
179 aFunc( item );
180 n++;
181 }
182 else if( typeMask[ PCB_VIA_T ] && item->Type() == PCB_VIA_T )
183 {
184 aFunc( item );
185 n++;
186 }
187 else if( typeMask[ PCB_ARC_T ] && item->Type() == PCB_ARC_T )
188 {
189 aFunc( item );
190 n++;
191 }
192 }
193 }
194
195 for( BOARD_ITEM* item : brd->Drawings() )
196 {
197 if( (item->GetLayerSet() & aLayers).any() )
198 {
199 if( typeMask[ PCB_DIMENSION_T ] && BaseType( item->Type() ) == PCB_DIMENSION_T )
200 {
201 if( !aFunc( item ) )
202 return n;
203
204 n++;
205 }
206 else if( typeMask[ PCB_SHAPE_T ] && item->Type() == PCB_SHAPE_T )
207 {
208 if( !aFunc( item ) )
209 return n;
210
211 n++;
212 }
213 else if( typeMask[ PCB_TEXT_T ] && item->Type() == PCB_TEXT_T )
214 {
215 if( !aFunc( item ) )
216 return n;
217
218 n++;
219 }
220 else if( typeMask[ PCB_TEXTBOX_T ] && item->Type() == PCB_TEXTBOX_T )
221 {
222 if( !aFunc( item ) )
223 return n;
224
225 n++;
226 }
227 else if( typeMask[ PCB_TARGET_T ] && item->Type() == PCB_TARGET_T )
228 {
229 if( !aFunc( item ) )
230 return n;
231
232 n++;
233 }
234 else if( BaseType( item->Type() ) == PCB_TABLE_T )
235 {
236 // A drill chart is a table for clearance purposes, so a PCB_TABLE_T mask
237 // has to reach one or its artwork escapes DRC entirely
238 if( typeMask[ PCB_TABLE_T ] )
239 {
240 if( !aFunc( item ) )
241 return n;
242
243 n++;
244 }
245
246 if( typeMask[ PCB_TABLECELL_T ] )
247 {
248 for( PCB_TABLECELL* cell : static_cast<PCB_TABLE*>( item )->GetCells() )
249 {
250 if( !aFunc( cell ) )
251 return n;
252
253 n++;
254 }
255 }
256 }
257 else if( typeMask[ PCB_BARCODE_T ] && item->Type() == PCB_BARCODE_T )
258 {
259 if( !aFunc( item ) )
260 return n;
261
262 n++;
263 }
264 }
265 }
266
267 if( typeMask[ PCB_ZONE_T ] )
268 {
269 for( ZONE* item : brd->Zones() )
270 {
271 if( ( item->GetLayerSet() & aLayers ).any() )
272 {
273 if( !aFunc( item ) )
274 return n;
275
276 n++;
277 }
278 }
279 }
280
281 for( FOOTPRINT* footprint : brd->Footprints() )
282 {
283 if( typeMask[ PCB_FIELD_T ] )
284 {
285 for( PCB_FIELD* field : footprint->GetFields() )
286 {
287 if( ( field->GetLayerSet() & aLayers ).any() )
288 {
289 if( !aFunc( field ) )
290 return n;
291
292 n++;
293 }
294 }
295 }
296
297 if( typeMask[ PCB_PAD_T ] )
298 {
299 for( PAD* pad : footprint->Pads() )
300 {
301 // Careful: if a pad has a hole then it pierces all layers
302 if( pad->HasHole() || ( pad->GetLayerSet() & aLayers ).any() )
303 {
304 if( !aFunc( pad ) )
305 return n;
306
307 n++;
308 }
309 }
310 }
311
312 for( BOARD_ITEM* dwg : footprint->GraphicalItems() )
313 {
314 if( (dwg->GetLayerSet() & aLayers).any() )
315 {
316 if( typeMask[ PCB_DIMENSION_T ] && BaseType( dwg->Type() ) == PCB_DIMENSION_T )
317 {
318 if( !aFunc( dwg ) )
319 return n;
320
321 n++;
322 }
323 else if( typeMask[ PCB_TEXT_T ] && dwg->Type() == PCB_TEXT_T )
324 {
325 if( !aFunc( dwg ) )
326 return n;
327
328 n++;
329 }
330 else if( typeMask[ PCB_TEXTBOX_T ] && dwg->Type() == PCB_TEXTBOX_T )
331 {
332 if( !aFunc( dwg ) )
333 return n;
334
335 n++;
336 }
337 else if( typeMask[ PCB_SHAPE_T ] && dwg->Type() == PCB_SHAPE_T )
338 {
339 if( !aFunc( dwg ) )
340 return n;
341
342 n++;
343 }
344 }
345 }
346
347 if( typeMask[ PCB_ZONE_T ] )
348 {
349 for( ZONE* zone : footprint->Zones() )
350 {
351 if( (zone->GetLayerSet() & aLayers).any() )
352 {
353 if( !aFunc( zone ) )
354 return n;
355
356 n++;
357 }
358 }
359 }
360
361 if( typeMask[ PCB_FOOTPRINT_T ] )
362 {
363 if( !aFunc( footprint ) )
364 return n;
365
366 n++;
367 }
368 }
369
370 return n;
371}
372
373
375{
376 if( const PCB_FIELD* field = dynamic_cast<const PCB_FIELD*>( aItem ) )
377 {
378 if( !field->IsVisible() )
379 return true;
380 }
381
382 return false;
383}
384
385
386wxString DRC_TEST_PROVIDER::formatMsg( const wxString& aFormatString, const wxString& aSource,
387 double aConstraint, double aActual, EDA_DATA_TYPE aType )
388{
389 wxString constraint_str = MessageTextFromValue( aConstraint, true, aType );
390 wxString actual_str = MessageTextFromValue( aActual, true, aType );
391
392 if( constraint_str == actual_str )
393 {
394 // Use more precise formatting if the message-text strings were equal.
395 constraint_str = StringFromValue( aConstraint, true, aType );
396 actual_str = StringFromValue( aActual, true, aType );
397 }
398
399 return wxString::Format( aFormatString, aSource, std::move( constraint_str ), std::move( actual_str ) );
400}
401
402
403wxString DRC_TEST_PROVIDER::formatMsg( const wxString& aFormatString, const wxString& aSource,
404 double aConstraint, double aActual, const wxString& aAdditionalParam,
405 EDA_DATA_TYPE aType )
406{
407 wxString constraint_str = MessageTextFromValue( aConstraint, true, aType );
408 wxString actual_str = MessageTextFromValue( aActual, true, aType );
409
410 if( constraint_str == actual_str )
411 {
412 // Use more precise formatting if the message-text strings were equal.
413 constraint_str = StringFromValue( aConstraint, true, aType );
414 actual_str = StringFromValue( aActual, true, aType );
415 }
416
417 return wxString::Format( aFormatString, aSource, std::move( constraint_str ), std::move( actual_str ),
418 aAdditionalParam );
419}
420
421
422wxString DRC_TEST_PROVIDER::formatMsg( const wxString& aFormatString, const wxString& aSource,
423 const EDA_ANGLE& aConstraint, const EDA_ANGLE& aActual )
424{
425 wxString constraint_str = MessageTextFromValue( aConstraint );
426 wxString actual_str = MessageTextFromValue( aActual );
427
428 if( constraint_str == actual_str )
429 {
430 // Use more precise formatting if the message-text strings were equal.
431 constraint_str = StringFromValue( aConstraint, true );
432 actual_str = StringFromValue( aActual, true );
433 }
434
435 return wxString::Format( aFormatString, aSource, std::move( constraint_str ), std::move( actual_str ) );
436}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
const ZONES & Zones() const
Definition board.h:467
const FOOTPRINTS & Footprints() const
Definition board.h:463
const TRACKS & Tracks() const
Definition board.h:461
const DRAWINGS & Drawings() const
Definition board.h:465
std::vector< DRC_TEST_PROVIDER * > m_providers
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...
static std::vector< KICAD_T > s_allBasicItemsButZones
virtual bool reportPhase(const wxString &aStageName)
void reportTwoShapeGeometry(std::shared_ptr< DRC_ITEM > &aDrcItem, const VECTOR2I &aMarkerPos, const SHAPE *aShape1, const SHAPE *aShape2, PCB_LAYER_ID aLayer, int aDistance)
int forEachGeometryItem(const std::vector< KICAD_T > &aTypes, const LSET &aLayers, const std::function< bool(BOARD_ITEM *)> &aFunc)
void reportTwoItemGeometry(std::shared_ptr< DRC_ITEM > &aDrcItem, const VECTOR2I &aMarkerPos, const BOARD_ITEM *aItem1, const BOARD_ITEM *aItem2, PCB_LAYER_ID aLayer, int aDistance)
void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer, const std::function< void(PCB_MARKER *)> &aPathGenerator=[](PCB_MARKER *){})
void reportTwoPointGeometry(std::shared_ptr< DRC_ITEM > &aDrcItem, const VECTOR2I &aMarkerPos, const VECTOR2I &ptA, const VECTOR2I &ptB, PCB_LAYER_ID aLayer)
static std::vector< KICAD_T > s_allBasicItems
bool isInvisibleText(const BOARD_ITEM *aItem) const
virtual const wxString GetName() const
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)
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
Definition pad.h:61
void SetPath(const std::vector< PCB_SHAPE > &aShapes, const VECTOR2I &aStart, const VECTOR2I &aEnd)
Definition pcb_marker.h:156
void SetEnd(const VECTOR2I &aEnd) override
void SetStart(const VECTOR2I &aStart) override
An abstract shape on 2D plane.
Definition shape.h:124
bool NearestPoints(const SHAPE *aOther, VECTOR2I &aPtThis, VECTOR2I &aPtOther) const
Return the two points that mark the closest distance between this shape and aOther.
UNITS_PROVIDER(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits)
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:70
#define REPORT_AUX(s)
@ SEGMENT
Definition eda_shape.h:56
EDA_DATA_TYPE
The type of unit.
Definition eda_units.h:34
EDA_UNITS
Definition eda_units.h:44
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
static const long long MM
constexpr KICAD_T BaseType(const KICAD_T aType)
Return the underlying type of the given type.
Definition typeinfo.h:259
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:70
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:80
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:89
@ MAX_STRUCT_TYPE_ID
Definition typeinfo.h:243
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition typeinfo.h:103
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:85
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:100
@ 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_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:93
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition typeinfo.h:99
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:87
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:78
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:79
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:90
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition typeinfo.h:92
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:86
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:88
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683