KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_drc_prepared_candidates.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
14
15#include <board.h>
17#include <drc/drc_engine.h>
18#include <drc/drc_rtree.h>
19#include <drc/drc_zone_index.h>
20#include <footprint.h>
21#include <pad.h>
22#include <pcb_track.h>
24#include <zone.h>
25
27
28#include <algorithm>
29#include <optional>
30#include <set>
31#include <string>
32#include <utility>
33#include <vector>
34
35
36namespace
37{
38
39struct PREPARED_CANDIDATES_FIXTURE
40{
41 void Load( const wxString& aRelPath )
42 {
43 KI_TEST::LoadBoard( m_settingsManager, aRelPath, m_board );
44 BOOST_REQUIRE( m_board );
45 m_board->GetDesignSettings().m_DRCEngine->RunTests( EDA_UNITS::MM, true, false );
46 BOOST_REQUIRE_GT( m_board->m_DRCMaxClearance, 0 );
47 }
48
49 SETTINGS_MANAGER m_settingsManager;
50 std::unique_ptr<BOARD> m_board;
51};
52
53
55void insertCopperItems( DRC_RTREE& aTree, BOARD* aBoard, PCB_LAYER_ID aLayer, int aPadding,
56 BOARD_ITEM* aExceptItem = nullptr, int aExceptPadding = 0 )
57{
58 auto insert =
59 [&]( BOARD_ITEM* aItem )
60 {
61 if( !aItem->IsOnLayer( aLayer ) )
62 return;
63
64 aTree.Insert( aItem, aLayer, CLEARANCE_CONSTRAINT,
65 aItem == aExceptItem ? aExceptPadding : aPadding );
66 };
67
68 for( PCB_TRACK* track : aBoard->Tracks() )
69 insert( track );
70
71 for( FOOTPRINT* footprint : aBoard->Footprints() )
72 {
73 for( PAD* pad : footprint->Pads() )
74 insert( pad );
75 }
76
77 aTree.Build();
78}
79
80
82bool isSubsequence( const std::vector<std::string>& aNeedle, const std::vector<std::string>& aHaystack )
83{
84 size_t pos = 0;
85
86 for( const std::string& entry : aNeedle )
87 {
88 while( pos < aHaystack.size() && aHaystack[pos] != entry )
89 ++pos;
90
91 if( pos == aHaystack.size() )
92 return false;
93
94 ++pos;
95 }
96
97 return true;
98}
99
100
101std::vector<BOARD_ITEM*> copperReferences( BOARD* aBoard, size_t aLimit )
102{
103 std::vector<BOARD_ITEM*> refs;
104
105 for( PCB_TRACK* track : aBoard->Tracks() )
106 {
107 if( refs.size() >= aLimit )
108 break;
109
110 refs.push_back( track );
111 }
112
113 size_t padLimit = refs.size() + aLimit;
114
115 for( FOOTPRINT* footprint : aBoard->Footprints() )
116 {
117 for( PAD* pad : footprint->Pads() )
118 {
119 if( refs.size() >= padLimit )
120 break;
121
122 refs.push_back( pad );
123 }
124 }
125
126 return refs;
127}
128
129
130std::vector<std::string> legacyCandidates( DRC_RTREE& aTree, BOARD_ITEM* aRef, PCB_LAYER_ID aLayer, int aClearance,
131 std::vector<std::string>* aFilterLog = nullptr,
132 const std::string& aReject = std::string() )
133{
134 std::vector<std::string> hits;
135
136 aTree.QueryColliding(
137 aRef, aLayer, aLayer,
138 [&]( BOARD_ITEM* aItem )
139 {
140 std::string uuid = aItem->m_Uuid.AsString().ToStdString();
141
142 if( aFilterLog )
143 aFilterLog->push_back( uuid );
144
145 return uuid != aReject;
146 },
147 [&]( BOARD_ITEM* aItem )
148 {
149 hits.push_back( aItem->m_Uuid.AsString().ToStdString() );
150 return true;
151 },
152 aClearance );
153
154 return hits;
155}
156
157
158std::vector<std::string> preparedCandidates( DRC_RTREE& aTree, BOARD_ITEM* aRef,
159 const std::shared_ptr<SHAPE>& aRefShape, PCB_LAYER_ID aLayer,
160 int aClearance, bool aCredit,
161 std::vector<std::string>* aFilterLog = nullptr,
162 const std::string& aReject = std::string(),
163 bool aCheckParentShapes = false )
164{
165 std::vector<std::string> hits;
166
168 aRef, aRefShape, aLayer,
169 [&]( BOARD_ITEM* aItem )
170 {
171 std::string uuid = aItem->m_Uuid.AsString().ToStdString();
172
173 if( aFilterLog )
174 aFilterLog->push_back( uuid );
175
176 return uuid != aReject;
177 },
178 [&]( BOARD_ITEM* aItem, const std::shared_ptr<SHAPE>& aParentShape )
179 {
180 BOOST_REQUIRE( aParentShape );
181
182 if( aCheckParentShapes )
183 {
184 // The substituted parent has to be what the provider used to build itself,
185 // which is the plain layer shape, not just something with the same bounds
186 std::shared_ptr<SHAPE> expected = aItem->GetEffectiveShape( aLayer );
188 BOOST_CHECK_EQUAL( aParentShape->Format( false ), expected->Format( false ) );
189 }
190
191 hits.push_back( aItem->m_Uuid.AsString().ToStdString() );
192 return true;
193 },
194 aClearance, aCredit );
195
196 return hits;
197}
198
199} // namespace
200
201
202BOOST_FIXTURE_TEST_CASE( DRCPreparedCopperQueryMatchesLegacy, PREPARED_CANDIDATES_FIXTURE )
203{
204 const wxString boards[] = { wxT( "issue12609" ), wxT( "issue6443" ), wxT( "issue22102" ) };
205
206 size_t totalHits = 0;
207 size_t widestQuery = 0;
208 size_t negativeClearanceQueries = 0;
209
210 for( const wxString& boardName : boards )
211 {
212 Load( boardName );
213
214 const int maxClearance = m_board->m_DRCMaxClearance;
215 const int clearances[] = { -maxClearance, 0, maxClearance / 2, maxClearance, maxClearance + 1 };
216
217 BOOST_REQUIRE( m_board->m_CopperItemRTreeCache );
218
219 for( BOARD_ITEM* ref : copperReferences( m_board.get(), 40 ) )
220 {
221 for( PCB_LAYER_ID layer : LSET( ref->GetLayerSet() & LSET::AllCuMask( m_board->GetCopperLayerCount() ) ) )
222 {
223 std::shared_ptr<SHAPE> refShape = ref->GetEffectiveShape( layer );
224 BOOST_REQUIRE( refShape );
225
226 for( int clearance : clearances )
227 {
228 std::vector<std::string> legacy =
229 legacyCandidates( *m_board->m_CopperItemRTreeCache, ref, layer, clearance );
230 std::vector<std::string> prepared =
231 preparedCandidates( *m_board->m_CopperItemRTreeCache, ref, refShape, layer, clearance,
232 true, nullptr, std::string(), true );
233
234 BOOST_CHECK_EQUAL_COLLECTIONS( legacy.begin(), legacy.end(), prepared.begin(), prepared.end() );
235
236 totalHits += legacy.size();
237 widestQuery = std::max( widestQuery, legacy.size() );
238
239 if( clearance < 0 )
240 ++negativeClearanceQueries;
241 }
242 }
243 }
244 }
245
246 // Several references have to actually collide, and at least one with more than one candidate,
247 // or the collection comparisons above are vacuous
248 BOOST_CHECK_GT( totalHits, 0u );
249 BOOST_CHECK_GT( widestQuery, 1u );
250 BOOST_CHECK_GT( negativeClearanceQueries, 0u );
251}
252
253
254BOOST_FIXTURE_TEST_CASE( DRCPreparedCopperFilterInvocationParity, PREPARED_CANDIDATES_FIXTURE )
255{
256 Load( wxT( "issue6443" ) );
257
258 const int maxClearance = m_board->m_DRCMaxClearance;
259 DRC_RTREE& tree = *m_board->m_CopperItemRTreeCache;
260
261 size_t plainInvocations = 0;
262 size_t creditInvocations = 0;
263 size_t rejections = 0;
264
265 for( BOARD_ITEM* ref : copperReferences( m_board.get(), 40 ) )
266 {
267 for( PCB_LAYER_ID layer : LSET( ref->GetLayerSet() & LSET::AllCuMask( m_board->GetCopperLayerCount() ) ) )
268 {
269 std::shared_ptr<SHAPE> refShape = ref->GetEffectiveShape( layer );
270
271 // Reject whichever candidate the legacy query sees first, so the memoized filter
272 // result is exercised on a parent that really is in the tree
273 std::vector<std::string> probe;
274 legacyCandidates( tree, ref, layer, maxClearance, &probe );
275
276 if( probe.empty() )
277 continue;
278
279 const std::string reject = probe.front();
280 ++rejections;
281
282 std::vector<std::string> legacyLog;
283 std::vector<std::string> plainLog;
284 std::vector<std::string> creditLog;
285
286 std::vector<std::string> legacy =
287 legacyCandidates( tree, ref, layer, maxClearance, &legacyLog, reject );
288 std::vector<std::string> plain = preparedCandidates( tree, ref, refShape, layer, maxClearance, false,
289 &plainLog, reject );
290 std::vector<std::string> credit = preparedCandidates( tree, ref, refShape, layer, maxClearance, true,
291 &creditLog, reject );
292
293 // Without credit the broad phase is the legacy one, so the filter has to be asked the
294 // same questions in the same order
295 BOOST_CHECK_EQUAL_COLLECTIONS( legacyLog.begin(), legacyLog.end(), plainLog.begin(), plainLog.end() );
296 BOOST_CHECK_EQUAL_COLLECTIONS( legacy.begin(), legacy.end(), plain.begin(), plain.end() );
297
298 // Credit only shrinks the query box, so it asks a subsequence of the same questions
299 // and still finds every collision
300 BOOST_CHECK( isSubsequence( creditLog, plainLog ) );
301 BOOST_CHECK_EQUAL_COLLECTIONS( legacy.begin(), legacy.end(), credit.begin(), credit.end() );
302
303 // Memoization: a parent is never handed to the filter twice
304 std::vector<std::string> sortedCredit = creditLog;
305 std::sort( sortedCredit.begin(), sortedCredit.end() );
306 BOOST_CHECK( std::adjacent_find( sortedCredit.begin(), sortedCredit.end() ) == sortedCredit.end() );
307
308 plainInvocations += plainLog.size();
309 creditInvocations += creditLog.size();
310 }
311 }
312
313 BOOST_CHECK_GT( rejections, 0u );
314
315 // Pruning pure filter invocations is the whole point of the credit, so an equal-call-count
316 // requirement would be wrong; what has to hold is that it never asks more
317 BOOST_CHECK_LT( creditInvocations, plainInvocations );
318}
319
320
321BOOST_FIXTURE_TEST_CASE( DRCPreparedCopperCreditUsesMinimumPadding, PREPARED_CANDIDATES_FIXTURE )
322{
323 // The falsifying case needs two real copper items whose bounding boxes are disjoint but which
324 // still collide within the board's worst clearance. Not every fixture has one, so scan.
325 const wxString candidates[] = { wxT( "issue12609" ), wxT( "issue6443" ), wxT( "issue22102" ),
326 wxT( "issue5978" ), wxT( "issue14008" ) };
327
328 const PCB_LAYER_ID layer = F_Cu;
329
330 BOARD_ITEM* reference = nullptr;
331 BOARD_ITEM* farCandidate = nullptr;
332 int maxClearance = 0;
333 DRC_RTREE uniform;
334
335 for( const wxString& boardName : candidates )
336 {
337 Load( boardName );
338 maxClearance = m_board->m_DRCMaxClearance;
339
340 uniform.clear();
341 insertCopperItems( uniform, m_board.get(), layer, maxClearance );
342
343 std::vector<BOARD_ITEM*> items = copperReferences( m_board.get(), 100000 );
344
345 for( BOARD_ITEM* ref : items )
346 {
347 if( !ref->IsOnLayer( layer ) )
348 continue;
349
350 std::vector<std::string> reachable = legacyCandidates( uniform, ref, layer, maxClearance );
351
352 for( BOARD_ITEM* candidate : items )
353 {
354 if( candidate == ref || !candidate->IsOnLayer( layer ) )
355 continue;
356
357 if( ref->GetBoundingBox().Intersects( candidate->GetBoundingBox() ) )
358 continue;
359
360 if( std::find( reachable.begin(), reachable.end(),
361 candidate->m_Uuid.AsString().ToStdString() ) == reachable.end() )
362 {
363 continue;
364 }
365
366 reference = ref;
367 farCandidate = candidate;
368 break;
369 }
370
371 if( reference )
372 break;
373 }
374
375 BOOST_TEST_MESSAGE( wxString::Format( "MINPAD %s maxClearance=%d qualifyingPair=%s", boardName,
376 maxClearance, reference ? "yes" : "no" ) );
377
378 if( reference )
379 break;
380 }
381
382 BOOST_REQUIRE( reference );
383 BOOST_REQUIRE( farCandidate );
384
385 // One item inserted with no padding drops the layer minimum to zero, which has to cost the
386 // query its whole credit
387 DRC_RTREE mixed;
388 insertCopperItems( mixed, m_board.get(), layer, maxClearance, farCandidate, 0 );
389
390 std::shared_ptr<SHAPE> refShape = reference->GetEffectiveShape( layer );
391 std::vector<std::string> expected = legacyCandidates( mixed, reference, layer, maxClearance );
392 std::vector<std::string> credit =
393 preparedCandidates( mixed, reference, refShape, layer, maxClearance, true );
394
395 BOOST_CHECK_EQUAL_COLLECTIONS( expected.begin(), expected.end(), credit.begin(), credit.end() );
396 BOOST_CHECK( std::find( credit.begin(), credit.end(), farCandidate->m_Uuid.AsString().ToStdString() )
397 != credit.end() );
398
399 // clear() drops the recorded padding with the entries; rebuilding on another layer must not
400 // inherit either
401 mixed.clear();
402 BOOST_CHECK_EQUAL( preparedCandidates( mixed, reference, refShape, layer, maxClearance, true ).size(), 0u );
403
404 insertCopperItems( mixed, m_board.get(), B_Cu, maxClearance / 2 );
405
406 for( BOARD_ITEM* ref : copperReferences( m_board.get(), 40 ) )
407 {
408 if( !ref->IsOnLayer( B_Cu ) )
409 continue;
410
411 std::shared_ptr<SHAPE> backShape = ref->GetEffectiveShape( B_Cu );
412 std::vector<std::string> legacy = legacyCandidates( mixed, ref, B_Cu, maxClearance );
413 std::vector<std::string> rebuilt =
414 preparedCandidates( mixed, ref, backShape, B_Cu, maxClearance, true );
415
416 BOOST_CHECK_EQUAL_COLLECTIONS( legacy.begin(), legacy.end(), rebuilt.begin(), rebuilt.end() );
417 }
418}
419
420
421BOOST_FIXTURE_TEST_CASE( DRCCreditCallSitesSatisfyContainment, PREPARED_CANDIDATES_FIXTURE )
422{
423 // Tracks and pads are the only two call sites that opt into the padding credit, and the credit
424 // is only sound where the item's bounding box contains the shape the query collides against.
425 // Nothing in the type system enforces that, so assert it directly: PAD::GetBoundingBox()
426 // contains the hole only because BuildEffectiveShapes() merges it in, and a refactor to a
427 // copper-only box would break DRC with no other test noticing.
428 const wxString boards[] = { wxT( "issue12609" ), wxT( "issue6443" ), wxT( "issue22102" ),
429 wxT( "issue14008" ), wxT( "reverse_via" ) };
430
431 size_t examined = 0;
432
433 for( const wxString& boardName : boards )
434 {
435 Load( boardName );
436
437 LSET copper = LSET::AllCuMask( m_board->GetCopperLayerCount() );
438
439 auto check =
440 [&]( BOARD_ITEM* aItem )
441 {
442 for( PCB_LAYER_ID layer : LSET( aItem->GetLayerSet() & copper ) )
443 {
444 std::shared_ptr<SHAPE> shape = aItem->GetEffectiveShape( layer );
445
446 if( !shape )
447 continue;
448
449 ++examined;
450 BOOST_CHECK_MESSAGE( aItem->GetBoundingBox().Contains( shape->BBox() ),
451 boardName + wxT( " " ) + aItem->m_Uuid.AsString()
452 + wxT( " does not contain its own shape" ) );
453 }
454 };
455
456 for( PCB_TRACK* track : m_board->Tracks() )
457 check( track );
458
459 for( FOOTPRINT* footprint : m_board->Footprints() )
460 {
461 for( PAD* pad : footprint->Pads() )
462 check( pad );
463 }
464 }
465
466 // A clean verdict over zero objects is not a clean verdict
467 BOOST_CHECK_GT( examined, 0u );
468}
469
470
471BOOST_FIXTURE_TEST_CASE( DRCGraphicBoundsDoNotContainTheirEffectiveShape, PREPARED_CANDIDATES_FIXTURE )
472{
473 // Padding credit is only sound where the item's bounding box contains the shape the query
474 // will collide against. Copper graphics do not satisfy that, which is why
475 // testGraphicClearances() opts out. Red if the two bounding boxes are ever reconciled, at
476 // which point the credit could be turned back on there.
477 Load( wxT( "issue22102" ) );
478
479 size_t copperGraphics = 0;
480 size_t uncontained = 0;
481
482 for( BOARD_ITEM* item : m_board->Drawings() )
483 {
484 PCB_LAYER_ID layer = item->GetLayer();
485
486 if( !IsCopperLayer( layer ) )
487 continue;
488
489 std::shared_ptr<SHAPE> shape = item->GetEffectiveShape( layer );
490
491 if( !shape )
492 continue;
493
494 ++copperGraphics;
495
496 if( !item->GetBoundingBox().Contains( shape->BBox() ) )
497 ++uncontained;
498 }
499
500 BOOST_CHECK_GT( copperGraphics, 0u );
501 BOOST_CHECK_GT( uncontained, 0u );
502}
503
504
505BOOST_FIXTURE_TEST_CASE( DRCZoneIndexMatchesOrderedLinearScan, PREPARED_CANDIDATES_FIXTURE )
506{
507 const wxString boards[] = { wxT( "fill_bad" ), wxT( "intersectingzones" ), wxT( "issue5750" ) };
508
509 size_t exercised = 0;
510 size_t multiCandidateQueries = 0;
511
512 for( const wxString& boardName : boards )
513 {
514 Load( boardName );
515
516 BOOST_REQUIRE( !m_board->m_DRCCopperZonesByLayer.empty() );
517
519 index.Build( m_board->m_DRCCopperZonesByLayer );
520
521 for( const auto& [layer, zones] : m_board->m_DRCCopperZonesByLayer )
522 {
523 for( ZONE* zone : zones )
524 {
525 BOX2I query = zone->GetBoundingBox();
526 query.Inflate( m_board->m_DRCMaxClearance );
527 query.Normalize();
528
529 std::vector<ZONE*> expected;
530 std::vector<ZONE*> actual;
531
532 for( ZONE* candidate : zones )
533 {
534 if( query.Intersects( candidate->GetBoundingBox() ) )
535 expected.push_back( candidate );
536 }
537
538 index.Query( layer, query, actual );
539 BOOST_CHECK_EQUAL_COLLECTIONS( expected.begin(), expected.end(), actual.begin(), actual.end() );
540
541 ++exercised;
542
543 if( actual.size() > 1 )
544 ++multiCandidateQueries;
545 }
546 }
547
548 // A layer the board has no copper zones on must simply come back empty
549 std::vector<ZONE*> absent;
550 index.Query( UNDEFINED_LAYER, BOX2I(), absent );
551 BOOST_CHECK( absent.empty() );
552
553 index.Clear();
554 index.Query( F_Cu, BOX2I(), absent );
555 BOOST_CHECK( absent.empty() );
556 }
557
558 BOOST_CHECK_GT( exercised, 0u );
559 BOOST_CHECK_GT( multiCandidateQueries, 0u );
560}
561
562
563BOOST_FIXTURE_TEST_CASE( DRCZonePairEnumerationMatchesNestedLoop, PREPARED_CANDIDATES_FIXTURE )
564{
565 const wxString boards[] = { wxT( "fill_bad" ), wxT( "intersectingzones" ), wxT( "issue5750" ) };
566
567 size_t totalPairs = 0;
568 size_t emptyLayers = 0;
569 size_t defaultBoxes = 0;
570 size_t noFillEntries = 0;
571
572 for( const wxString& boardName : boards )
573 {
574 Load( boardName );
575
576 // Same pre-sort the provider does
577 std::map<PCB_LAYER_ID, std::vector<size_t>> zoneIdxByLayer;
578
579 for( size_t ii = 0; ii < m_board->m_DRCCopperZones.size(); ++ii )
580 {
581 ZONE* zone = m_board->m_DRCCopperZones[ii];
582
583 if( zone->IsTeardropArea() )
584 continue;
585
586 for( PCB_LAYER_ID layer : zone->GetLayerSet() )
587 {
588 if( IsCopperLayer( layer ) )
589 zoneIdxByLayer[layer].push_back( ii );
590 }
591 }
592
593 for( const auto& [layer, indices] : zoneIdxByLayer )
594 {
595 auto fillBox =
596 [&]( size_t aIndex ) -> std::optional<BOX2I>
597 {
598 if( SHAPE_POLY_SET* poly = m_board->m_DRCCopperZones[aIndex]->GetFill( layer ) )
599 return poly->BBoxFromCaches();
600
601 return std::nullopt;
602 };
603
604 std::vector<std::string> expected;
605
606 for( size_t ia = 0; ia < indices.size(); ++ia )
607 {
608 SHAPE_POLY_SET* polyA = m_board->m_DRCCopperZones[indices[ia]]->GetFill( layer );
609
610 if( !polyA )
611 {
612 ++noFillEntries;
613 continue;
614 }
615
616 if( polyA->BBoxFromCaches() == BOX2I() )
617 ++defaultBoxes;
618
619 for( size_t ib = ia + 1; ib < indices.size(); ++ib )
620 {
621 SHAPE_POLY_SET* polyB = m_board->m_DRCCopperZones[indices[ib]]->GetFill( layer );
622
623 if( !polyB || !polyA->BBoxFromCaches().Intersects( polyB->BBoxFromCaches() ) )
624 continue;
625
626 expected.push_back( std::to_string( indices[ia] ) + "-" + std::to_string( indices[ib] ) );
627 }
628 }
629
630 std::vector<std::pair<size_t, size_t>> pairs = CollectOverlappingPairs( indices, fillBox );
631 std::vector<std::string> actual;
632
633 for( const auto& [first, second] : pairs )
634 actual.push_back( std::to_string( first ) + "-" + std::to_string( second ) );
635
636 BOOST_CHECK_EQUAL_COLLECTIONS( expected.begin(), expected.end(), actual.begin(), actual.end() );
637
638 totalPairs += actual.size();
639
640 if( pairs.empty() )
641 ++emptyLayers;
642
643 std::set<size_t> participating;
644
645 for( const auto& [first, second] : pairs )
646 {
647 participating.insert( first );
648 participating.insert( second );
649 }
650
651 // Independent of the expected-pair comparison above, a zone the provider would build
652 // a segment tree for has to be one of this layer's filled zones
653 for( size_t idx : participating )
654 {
655 bool known = std::find( indices.begin(), indices.end(), idx ) != indices.end();
656
657 BOOST_CHECK( known );
658
659 // Guarded so an out-of-range index reports a clean failure instead of faulting
660 if( known )
661 BOOST_CHECK( m_board->m_DRCCopperZones[idx]->GetFill( layer ) != nullptr );
662 }
663 }
664 }
665
666 BOOST_TEST_MESSAGE( wxString::Format( "ZONEPAIRS totalPairs=%zu emptyLayers=%zu defaultBoxes=%zu "
667 "noFillEntries=%zu",
668 totalPairs, emptyLayers, defaultBoxes, noFillEntries ) );
669
670 BOOST_CHECK_GT( totalPairs, 0u );
671 BOOST_CHECK_GT( emptyLayers, 0u );
672
673 // No fixture here produces a zone/layer with no fill or a default-origin BBoxFromCaches(),
674 // so those two branches stay unasserted
675 BOOST_TEST_MESSAGE( wxString::Format( "degenerate paths unreached by real fixtures: "
676 "defaultBoxes=%zu noFillEntries=%zu",
677 defaultBoxes, noFillEntries ) );
678}
679
KICAD_PLUGIN_EXPORT SCENEGRAPH * Load(char const *aFileName)
Read a model file and creates a generic display structure.
int index
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:346
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:410
const FOOTPRINTS & Footprints() const
Definition board.h:464
const TRACKS & Tracks() const
Definition board.h:462
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:143
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:165
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:308
Implement an R-tree for fast spatial and layer indexing of connectable items.
Definition drc_rtree.h:46
void Insert(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer, DRC_CONSTRAINT_T aConstraintType, int aWorstClearance=0, bool aAtomicTables=false)
Insert an item into the tree on a particular layer with an optional worst clearance.
Definition drc_rtree.h:94
int QueryColliding(BOARD_ITEM *aRefItem, PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer, std::function< bool(BOARD_ITEM *)> aFilter=nullptr, std::function< bool(BOARD_ITEM *)> aVisitor=nullptr, int aClearance=0) const
This is a fast test which essentially does bounding-box overlap given a worst-case clearance.
Definition drc_rtree.h:287
int QueryCollidingPreparedCopper(BOARD_ITEM *aRefItem, const std::shared_ptr< SHAPE > &aRefShape, PCB_LAYER_ID aTargetLayer, std::function< bool(BOARD_ITEM *)> aFilter, std::function< bool(BOARD_ITEM *, const std::shared_ptr< SHAPE > &)> aVisitor, int aClearance=0, bool aUsePaddingCredit=false) const
Same broad phase as QueryColliding(), but the caller supplies the reference shape and the visitor als...
Definition drc_rtree.h:366
void clear()
Remove all items from the RTree.
Definition drc_rtree.h:180
void Build()
Finalize all pending inserts by bulk-building packed R-trees from the staged items.
Definition drc_rtree.h:169
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:270
const KIID m_Uuid
Definition eda_item.h:599
wxString AsString() const
Definition kiid.cpp:264
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
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:595
Definition pad.h:61
Represent a set of closed polygons.
const BOX2I BBoxFromCaches() const
Handle a list of polygons defining a copper zone.
Definition zone.h:70
bool IsTeardropArea() const
Definition zone.h:807
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition zone.h:133
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:51
std::vector< std::pair< size_t, size_t > > CollectOverlappingPairs(const std::vector< size_t > &aOrderedIndices, BOX_FN aBox)
Enumerate the pairs of aOrderedIndices whose boxes overlap, in the order a nested loop over the vecto...
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
@ B_Cu
Definition layer_ids.h:61
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ F_Cu
Definition layer_ids.h:60
void LoadBoard(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< BOARD > &aBoard)
BOOST_CHECK_EQUAL_COLLECTIONS(mixed.begin(), mixed.end(), expMixed.begin(), expMixed.end())
BOOST_FIXTURE_TEST_CASE(DRCPreparedCopperQueryMatchesLegacy, PREPARED_CANDIDATES_FIXTURE)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
VECTOR3I expected(15, 30, 45)
static std::vector< int > candidates(const SEGMENT_INDEX &aIndex, const SEG &aQuery, int aPadding)
int clearance
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
int actual
BOOST_CHECK_EQUAL(result, "25.4")