KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
drc_test_provider_silk_clearance.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 <common.h>
25#include <board.h>
26#include <pcb_track.h>
28#include <geometry/seg.h>
29#include <drc/drc_engine.h>
30#include <drc/drc_item.h>
31#include <drc/drc_rule.h>
33#include <drc/drc_rtree.h>
34
35/*
36 Silk to silk clearance test. Check all silkscreen features against each other.
37 Errors generated:
38 - DRCE_OVERLAPPING_SILK
39
40*/
41
43{
44public:
46 m_board( nullptr ),
48 {
49 }
50
52 {
53 }
54
55 virtual bool Run() override;
56
57 virtual const wxString GetName() const override
58 {
59 return wxT( "silk_clearance" );
60 };
61
62 virtual const wxString GetDescription() const override
63 {
64 return wxT( "Tests for overlapping silkscreen features." );
65 }
66
67private:
68
71};
72
73
75{
76 const int progressDelta = 500;
77
79
80 // If the soldermask min width is greater than 0 then we must use a healing algorithm to generate
81 // a whole-board soldermask poly, and then test against that. However, that can't deal well with
82 // DRC exclusions (as any change anywhere on the board that affects the soldermask will null the
83 // associated exclusions), so we only use that when soldermask min width is > 0.
84 bool checkIndividualMaskItems = m_board->GetDesignSettings().m_SolderMaskMinWidth <= 0;
85
87 && ( m_drcEngine->IsErrorLimitExceeded( DRCE_SILK_MASK_CLEARANCE) || !checkIndividualMaskItems ) )
88 {
89 return true; // continue with other tests
90 }
91
92 DRC_CONSTRAINT worstClearanceConstraint;
94
95 if( m_drcEngine->QueryWorstConstraint( SILK_CLEARANCE_CONSTRAINT, worstClearanceConstraint ) )
96 m_largestClearance = worstClearanceConstraint.m_Value.Min();
97
98 reportAux( wxT( "Worst clearance : %d nm" ), m_largestClearance );
99
100 if( !reportPhase( _( "Checking silkscreen for overlapping items..." ) ) )
101 return false; // DRC cancelled
102
103 DRC_RTREE silkTree;
104 DRC_RTREE targetTree;
105 int ii = 0;
106 int items = 0;
107
108 auto countItems =
109 [&]( BOARD_ITEM* item ) -> bool
110 {
111 ++items;
112 return true;
113 };
114
115 auto addToSilkTree =
116 [&]( BOARD_ITEM* item ) -> bool
117 {
118 if( !reportProgress( ii++, items, progressDelta ) )
119 return false;
120
121 for( PCB_LAYER_ID layer : { F_SilkS, B_SilkS } )
122 {
123 if( item->IsOnLayer( layer ) )
124 silkTree.Insert( item, layer );
125 }
126
127 return true;
128 };
129
130 auto addToTargetTree =
131 [&]( BOARD_ITEM* item ) -> bool
132 {
133 if( !reportProgress( ii++, items, progressDelta ) )
134 return false;
135
136 for( PCB_LAYER_ID layer : item->GetLayerSet().Seq() )
137 targetTree.Insert( item, layer );
138
139 return true;
140 };
141
143
146 countItems );
147
148 forEachGeometryItem( s_allBasicItems, LSET( { F_SilkS, B_SilkS } ), addToSilkTree );
149
152 addToTargetTree );
153
154 reportAux( wxT( "Testing %d silkscreen features against %d board items." ),
155 silkTree.size(),
156 targetTree.size() );
157
158 const std::vector<DRC_RTREE::LAYER_PAIR> layerPairs =
159 {
178 };
179
180 targetTree.QueryCollidingPairs( &silkTree, layerPairs,
181 [&]( const DRC_RTREE::LAYER_PAIR& aLayers, DRC_RTREE::ITEM_WITH_SHAPE* aRefItemShape,
182 DRC_RTREE::ITEM_WITH_SHAPE* aTestItemShape, bool* aCollisionDetected ) -> bool
183 {
184 BOARD_ITEM* refItem = aRefItemShape->parent;
185 const SHAPE* refShape = aRefItemShape->shape;
186 BOARD_ITEM* testItem = aTestItemShape->parent;
187 const SHAPE* testShape = aTestItemShape->shape;
188
189 std::shared_ptr<SHAPE> hole;
190
191 if( ( m_drcEngine->IsErrorLimitExceeded( DRCE_SILK_MASK_CLEARANCE) || !checkIndividualMaskItems )
193 {
194 return false;
195 }
196
197 if( isInvisibleText( refItem ) || isInvisibleText( testItem ) )
198 return true;
199
200 if( testItem->IsTented( aLayers.first ) )
201 {
202 if( testItem->HasHole() )
203 {
204 hole = testItem->GetEffectiveHoleShape();
205 testShape = hole.get();
206 }
207 else
208 {
209 return true;
210 }
211 }
212
213 int errorCode = DRCE_OVERLAPPING_SILK;
215 refItem, testItem, aLayers.second );
216 int minClearance = -1;
217
218 if( !constraint.IsNull() && constraint.GetSeverity() != RPT_SEVERITY_IGNORE )
219 minClearance = constraint.GetValue().Min();
220
221 if( aLayers.second == F_Mask || aLayers.second == B_Mask )
222 {
223 if( checkIndividualMaskItems )
224 minClearance = std::max( minClearance, 0 );
225
226 errorCode = DRCE_SILK_MASK_CLEARANCE;
227 }
228
229 if( minClearance < 0 )
230 return true;
231
232 int actual;
233 VECTOR2I pos;
234
235 // Graphics are often compound shapes so ignore collisions between shapes in a
236 // single footprint or on the board (both parent footprints will be nullptr).
237 if( refItem->Type() == PCB_SHAPE_T && testItem->Type() == PCB_SHAPE_T
238 && refItem->GetParentFootprint() == testItem->GetParentFootprint() )
239 {
240 return true;
241 }
242
243 // Collide (and generate violations) based on a well-defined order so that
244 // exclusion checking against previously-generated violations will work.
245 if( aLayers.first == aLayers.second )
246 {
247 if( refItem->m_Uuid > testItem->m_Uuid )
248 {
249 std::swap( refItem, testItem );
250 std::swap( refShape, testShape );
251 }
252 }
253
254 if( refShape->Collide( testShape, minClearance, &actual, &pos ) )
255 {
256 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( errorCode );
257
258 if( minClearance > 0 )
259 {
260 wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
261 constraint.GetParentRule()->m_Name,
262 minClearance,
263 actual );
264
265 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
266 }
267
268 drcItem->SetItems( refItem, testItem );
269 drcItem->SetViolatingRule( constraint.GetParentRule() );
270
271 reportViolation( drcItem, pos, aLayers.second );
272
273 *aCollisionDetected = true;
274 }
275
276 return true;
277 },
278 m_largestClearance,
279 [&]( int aCount, int aSize ) -> bool
280 {
281 return reportProgress( aCount, aSize, progressDelta );
282 } );
283
284 reportRuleStatistics();
285
286 return !m_drcEngine->IsCancelled();
287}
288
289
290namespace detail
291{
293}
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:78
virtual bool IsTented(PCB_LAYER_ID aLayer) const
Checks if the given object is tented (its copper shape is covered by solder mask) on a given side of ...
Definition: board_item.h:170
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:297
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:946
SEVERITY GetSeverity() const
Definition: drc_rule.h:173
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:152
MINOPTMAX< int > m_Value
Definition: drc_rule.h:190
bool IsNull() const
Definition: drc_rule.h:147
BOARD * GetBoard() const
Definition: drc_engine.h:96
bool IsErrorLimitExceeded(int error_code)
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
Definition: drc_engine.cpp:693
bool QueryWorstConstraint(DRC_CONSTRAINT_T aRuleId, DRC_CONSTRAINT &aConstraint)
Implement an R-tree for fast spatial and layer indexing of connectable items.
Definition: drc_rtree.h:48
void Insert(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer, int aWorstClearance=0)
Insert an item into the tree on a particular layer with an optional worst clearance.
Definition: drc_rtree.h:104
size_t size() const
Return the number of items in the tree.
Definition: drc_rtree.h:535
std::pair< PCB_LAYER_ID, PCB_LAYER_ID > LAYER_PAIR
Definition: drc_rtree.h:440
int QueryCollidingPairs(DRC_RTREE *aRefTree, std::vector< LAYER_PAIR > aLayerPairs, std::function< bool(const LAYER_PAIR &, ITEM_WITH_SHAPE *, ITEM_WITH_SHAPE *, bool *aCollision)> aVisitor, int aMaxClearance, std::function< bool(int, int)> aProgressReporter) const
Definition: drc_rtree.h:455
virtual const wxString GetName() const override
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
virtual const wxString GetDescription() const override
Represent a DRC "provider" which runs some DRC functions over a BOARD and spits out DRC_ITEM and posi...
virtual bool reportPhase(const wxString &aStageName)
int forEachGeometryItem(const std::vector< KICAD_T > &aTypes, const LSET &aLayers, const std::function< bool(BOARD_ITEM *)> &aFunc)
static std::vector< KICAD_T > s_allBasicItems
DRC_ENGINE * m_drcEngine
bool isInvisibleText(const BOARD_ITEM *aItem) const
void reportAux(const wxString &aMsg)
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
static const LSET & FrontMask()
Return a mask holding all technical layers and the external CU layer on front side.
Definition: lset.cpp:708
static const LSET & BackMask()
Return a mask holding all technical layers and the external CU layer on back side.
Definition: lset.cpp:715
T Min() const
Definition: minoptmax.h:33
An abstract shape on 2D plane.
Definition: shape.h:126
The common library.
@ DRCE_SILK_MASK_CLEARANCE
Definition: drc_item.h:96
@ DRCE_OVERLAPPING_SILK
Definition: drc_item.h:101
@ SILK_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:56
#define _(s)
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ F_CrtYd
Definition: layer_ids.h:116
@ B_Adhes
Definition: layer_ids.h:103
@ Edge_Cuts
Definition: layer_ids.h:112
@ F_Paste
Definition: layer_ids.h:104
@ F_Adhes
Definition: layer_ids.h:102
@ B_Mask
Definition: layer_ids.h:98
@ B_Cu
Definition: layer_ids.h:65
@ F_Mask
Definition: layer_ids.h:97
@ B_Paste
Definition: layer_ids.h:105
@ F_Fab
Definition: layer_ids.h:119
@ Margin
Definition: layer_ids.h:113
@ F_SilkS
Definition: layer_ids.h:100
@ B_CrtYd
Definition: layer_ids.h:115
@ B_SilkS
Definition: layer_ids.h:101
@ F_Cu
Definition: layer_ids.h:64
@ B_Fab
Definition: layer_ids.h:118
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
@ RPT_SEVERITY_IGNORE
int actual
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88