KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_cache_generator.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 <common.h>
22#include <pad.h>
23#include <pcb_board_outline.h>
24#include <footprint.h>
25#include <thread_pool.h>
26#include <zone.h>
28#include <drc/drc_engine.h>
29#include <drc/drc_rtree.h>
31#include <mutex>
32
34{
35 m_board = m_drcEngine->GetBoard();
36
37 // Everything below appends to the board's DRC caches rather than replacing them, so they
38 // have to start out empty.
39 m_board->IncrementTimeStamp();
40
41 int& largestClearance = m_board->m_DRCMaxClearance;
42 int& largestPhysicalClearance = m_board->m_DRCMaxPhysicalClearance;
43 DRC_CONSTRAINT worstConstraint;
44 LSET boardCopperLayers = LSET::AllCuMask( m_board->GetCopperLayerCount() );
46
47 largestClearance = std::max( largestClearance, m_board->GetMaxClearanceValue() );
48
49 // Only consider unconditional constraints for the global maximum. Conditional constraints
50 // (like the barcode physical clearance default) apply only to specific item types and
51 // should not inflate the R-tree query radius for all items on the board.
52 if( m_drcEngine->QueryWorstConstraint( PHYSICAL_CLEARANCE_CONSTRAINT, worstConstraint, true ) )
53 largestPhysicalClearance = worstConstraint.GetValue().Min();
54
55 if( m_drcEngine->QueryWorstConstraint( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, worstConstraint, true ) )
56 largestPhysicalClearance = std::max( largestPhysicalClearance, worstConstraint.GetValue().Min() );
57
58 // If the unconditional max is 0, check for conditional constraints that may still apply.
59 // User-defined conditional rules always need the test to run. The implicit barcode rule
60 // only needs the test if barcodes actually exist on the board.
61 if( largestPhysicalClearance <= 0 )
62 {
63 int conditionalMax = 0;
64
65 if( m_drcEngine->QueryWorstConstraint( PHYSICAL_CLEARANCE_CONSTRAINT, worstConstraint ) )
66 conditionalMax = worstConstraint.GetValue().Min();
67
68 if( m_drcEngine->QueryWorstConstraint( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, worstConstraint ) )
69 conditionalMax = std::max( conditionalMax, worstConstraint.GetValue().Min() );
70
71 if( conditionalMax > 0 )
72 {
73 if( m_drcEngine->HasUserDefinedPhysicalConstraint() )
74 {
75 largestPhysicalClearance = conditionalMax;
76 }
77 else
78 {
79 bool hasMatchingItems = false;
80
82 [&]( BOARD_ITEM* item ) -> bool
83 {
84 hasMatchingItems = true;
85 return false;
86 } );
87
88 if( hasMatchingItems )
89 largestPhysicalClearance = conditionalMax;
90 }
91 }
92 }
93
94 // Ensure algorithmic safety
95 largestClearance = std::min( largestClearance, INT_MAX / 3 );
96 largestPhysicalClearance = std::min( largestPhysicalClearance, INT_MAX / 3 );
97
98 std::set<ZONE*> allZones;
99
100 auto cacheBBoxes =
101 []( ZONE* zone, const LSET& copperLayers )
102 {
103 if( !zone->GetParentFootprint() )
104 zone->Outline()->BuildBBoxCaches();
105
106 for( PCB_LAYER_ID layer : copperLayers )
107 {
108 if( SHAPE_POLY_SET* fill = zone->GetFill( layer ) )
109 fill->BuildBBoxCaches();
110 }
111 };
112
113 for( ZONE* zone : m_board->Zones() )
114 {
115 allZones.insert( zone );
116
117 if( !zone->GetIsRuleArea() )
118 {
119 m_board->m_DRCZones.push_back( zone );
120
121 LSET zoneCopperLayers = zone->GetLayerSet() & boardCopperLayers;
122
123 if( zoneCopperLayers.any() )
124 {
125 cacheBBoxes( zone, zoneCopperLayers );
126 m_board->m_DRCCopperZones.push_back( zone );
127 }
128 }
129 }
130
131 for( FOOTPRINT* footprint : m_board->Footprints() )
132 {
133 for( ZONE* zone : footprint->Zones() )
134 {
135 allZones.insert( zone );
136
137 if( !zone->GetIsRuleArea() )
138 {
139 m_board->m_DRCZones.push_back( zone );
140
141 LSET zoneCopperLayers = zone->GetLayerSet() & boardCopperLayers;
142
143 if( zoneCopperLayers.any() )
144 {
145 cacheBBoxes( zone, zoneCopperLayers );
146 m_board->m_DRCCopperZones.push_back( zone );
147 }
148 }
149 }
150 }
151
152 for( ZONE* zone : m_board->m_DRCCopperZones )
153 {
154 LSET zoneCopperLayers = zone->GetLayerSet() & boardCopperLayers;
155
156 for( PCB_LAYER_ID layer : zoneCopperLayers )
157 m_board->m_DRCCopperZonesByLayer[layer].push_back( zone );
158 }
159
160 size_t count = 0;
161 std::atomic<size_t> done( 1 );
162
163 auto countItems =
164 [&]( BOARD_ITEM* item ) -> bool
165 {
166 ++count;
167 return true;
168 };
169
170 auto addToCopperTree =
171 [&]( BOARD_ITEM* item ) -> bool
172 {
173 if( m_drcEngine->IsCancelled() )
174 return false;
175
176 LSET copperLayers = item->GetLayerSet() & boardCopperLayers;
177
178 // Special-case pad holes which pierce all the copper layers
179 if( item->Type() == PCB_PAD_T )
180 {
181 PAD* pad = static_cast<PAD*>( item );
182
183 if( pad->HasHole() )
184 copperLayers = boardCopperLayers;
185 }
186
187 copperLayers.RunOnLayers(
188 [&]( PCB_LAYER_ID layer )
189 {
190 m_board->m_CopperItemRTreeCache->Insert( item, layer, CLEARANCE_CONSTRAINT,
191 largestClearance );
192 } );
193
194 done.fetch_add( 1 );
195 return true;
196 };
197
198 if( !reportPhase( _( "Gathering copper items..." ) ) )
199 return false; // DRC cancelled
200
201 static const std::vector<KICAD_T> itemTypes = {
203 PCB_PAD_T,
209 };
210
211 forEachGeometryItem( itemTypes, boardCopperLayers, countItems );
212
213 std::future<void> retn = tp.submit_task(
214 [&]()
215 {
216 std::unique_lock<std::shared_mutex> writeLock( m_board->m_CachesMutex );
217
218 // Always start from an empty tree: the traversal below re-inserts every copper
219 // item, and a DRC_RTREE stops accepting inserts once it has been built.
220 m_board->m_CopperItemRTreeCache = std::make_shared<DRC_RTREE>();
221
222 forEachGeometryItem( itemTypes, boardCopperLayers, addToCopperTree );
223 m_board->m_CopperItemRTreeCache->Build();
224 } );
225
226 std::future_status status = retn.wait_for( std::chrono::milliseconds( 250 ) );
227
228 while( status != std::future_status::ready )
229 {
230 reportProgress( done, count );
231 status = retn.wait_for( std::chrono::milliseconds( 250 ) );
232 }
233
234 if( !reportPhase( _( "Tessellating copper zones..." ) ) )
235 return false; // DRC cancelled
236
237 // Cache zone bounding boxes, triangulation, copper zone rtrees, and footprint courtyards
238 // before we start.
239
240 for( FOOTPRINT* footprint : m_board->Footprints() )
241 {
242 footprint->BuildCourtyardCaches();
243 footprint->BuildNetTieCache();
244 }
245
246 std::vector<std::future<size_t>> returns;
247
248 returns.reserve( allZones.size() );
249
250 auto cache_zones =
251 [this, &done]( ZONE* aZone ) -> size_t
252 {
253 if( m_drcEngine->IsCancelled() )
254 return 0;
255
256 aZone->CacheBoundingBox();
257 aZone->CacheTriangulation();
258
259 if( !aZone->GetIsRuleArea() && aZone->IsOnCopperLayer() )
260 {
261 std::unique_ptr<DRC_RTREE> rtree = std::make_unique<DRC_RTREE>();
262
263 aZone->GetLayerSet().RunOnLayers(
264 [&]( PCB_LAYER_ID layer )
265 {
266 if( IsCopperLayer( layer ) )
267 rtree->Insert( aZone, layer, CLEARANCE_CONSTRAINT );
268 } );
269
270 rtree->Build();
271
272 {
273 std::unique_lock<std::shared_mutex> writeLock( m_board->m_CachesMutex );
274 m_board->m_CopperZoneRTreeCache[ aZone ] = std::move( rtree );
275 }
276
277 done.fetch_add( 1 );
278 }
279
280 return 1;
281 };
282
283 for( ZONE* zone : allZones )
284 {
285 returns.emplace_back( tp.submit_task(
286 [cache_zones, zone]
287 {
288 return cache_zones( zone );
289 } ) );
290 }
291
292 done.store( 1 );
293
294 for( const std::future<size_t>& ret : returns )
295 {
296 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
297
298 while( status != std::future_status::ready )
299 {
300 reportProgress( done, allZones.size() );
301 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
302 }
303 }
304
305 m_board->m_ZoneIsolatedIslandsMap.clear();
306
307 for( ZONE* zone : m_board->Zones() )
308 {
309 if( !zone->GetIsRuleArea() && !zone->IsTeardropArea() && !zone->IsCopperThieving() )
310 {
311 zone->GetLayerSet().RunOnLayers(
312 [&]( PCB_LAYER_ID layer )
313 {
314 m_board->m_ZoneIsolatedIslandsMap[ zone ][ layer ] = ISOLATED_ISLANDS();
315 } );
316 }
317 }
318
319 m_board->UpdateBoardOutline();
320
321 if( m_board->BoardOutline() )
322 m_board->BoardOutline()->GetOutline().BuildBBoxCaches();
323
324 std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
325
326 connectivity->ClearRatsnest();
327 connectivity->Build( m_board, m_drcEngine->GetProgressReporter() );
328 connectivity->FillIsolatedIslandsMap( m_board->m_ZoneIsolatedIslandsMap, true );
329
330 return !m_drcEngine->IsCancelled();
331}
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
FOOTPRINT * GetParentFootprint() const
virtual bool Run() override
Discard the board's run-time DRC caches and regenerate them from scratch.
const MINOPTMAX< int > & GetValue() const
Definition drc_rule.h:200
virtual bool reportPhase(const wxString &aStageName)
int forEachGeometryItem(const std::vector< KICAD_T > &aTypes, const LSET &aLayers, const std::function< bool(BOARD_ITEM *)> &aFunc)
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 & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:604
void RunOnLayers(const std::function< void(PCB_LAYER_ID)> &aFunction) const
Execute a function on each layer of the LSET.
Definition lset.h:263
static const LSET & AllLayersMask()
Definition lset.cpp:637
T Min() const
Definition minoptmax.h:29
Definition pad.h:61
Represent a set of closed polygons.
void BuildBBoxCaches() const
Construct BBoxCaches for Contains(), below.
Handle a list of polygons defining a copper zone.
Definition zone.h:70
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition zone.h:807
SHAPE_POLY_SET * Outline()
Definition zone.h:418
bool IsCopperThieving() const
Definition zone.h:349
SHAPE_POLY_SET * GetFill(PCB_LAYER_ID aLayer)
Definition zone.h:699
bool IsTeardropArea() const
Definition zone.h:782
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition zone.h:133
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:83
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:51
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition drc_rule.h:82
#define _(s)
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:703
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
A struct recording the isolated and single-pad islands within a zone.
Definition zone.h:57
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
static thread_pool * tp
BS::priority_thread_pool thread_pool
Definition thread_pool.h:27
@ 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
@ 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_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:93
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:87
@ 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