KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_rtree.h
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 * Copyright (C) 2020 CERN
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 3
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21#ifndef DRC_RTREE_H_
22#define DRC_RTREE_H_
23
24#include <board_item.h>
25#include <pcb_field.h>
26#include <algorithm>
27#include <memory>
28#include <unordered_set>
29#include <set>
30#include <vector>
31
33#include <geometry/shape.h>
35#include <math/vector2d.h>
36#include "geometry/shape_null.h"
37#include "board.h"
38
39#define ATOMIC_TABLES true
40
46{
47public:
49 {
50 ITEM_WITH_SHAPE( BOARD_ITEM *aParent, const SHAPE* aShape,
51 std::shared_ptr<SHAPE> aParentShape ) :
52 parent( aParent ),
53 shape( aShape ),
54 shapeStorage( nullptr ),
55 parentShape( std::move( aParentShape ) )
56 {};
57
58 ITEM_WITH_SHAPE( BOARD_ITEM *aParent, const std::shared_ptr<SHAPE>& aShape,
59 std::shared_ptr<SHAPE> aParentShape ) :
60 parent( aParent ),
61 shape( aShape.get() ),
62 shapeStorage( aShape ),
63 parentShape( std::move( aParentShape ) )
64 {};
65
67 const SHAPE* shape;
68 std::shared_ptr<SHAPE> shapeStorage;
69
71 std::shared_ptr<SHAPE> parentShape;
72 };
73
74private:
76 using drc_rtree_builder = typename drc_rtree::Builder;
77
78public:
80 {
81 m_count = 0;
82 }
83
85 {
86 for( ITEM_WITH_SHAPE* p : m_owned )
87 delete p;
88 }
89
94 void Insert( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, DRC_CONSTRAINT_T aConstraintType,
95 int aWorstClearance = 0, bool aAtomicTables = false )
96 {
97 Insert( aItem, aLayer, aLayer, aConstraintType, aWorstClearance, aAtomicTables );
98 }
99
104 void Insert( BOARD_ITEM* aItem, PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer,
105 DRC_CONSTRAINT_T aConstraintType, int aWorstClearance, bool aAtomicTables = false )
106 {
107 wxCHECK( aTargetLayer != UNDEFINED_LAYER, /* void */ );
108 wxCHECK_MSG( !m_tree.count( aTargetLayer ), /* void */, wxT( "Insert after Build() is silently wrong" ) );
109
110 if( aItem->Type() == PCB_FIELD_T && !static_cast<PCB_FIELD*>( aItem )->IsVisible() )
111 return;
112
113 BOARD_ITEM* parent = aItem;
114
115 if( aAtomicTables && aItem->Type() == PCB_TABLECELL_T )
116 parent = aItem->GetParent();
117
118 std::vector<const SHAPE*> subshapes;
119 std::shared_ptr<SHAPE> shape = aItem->GetEffectiveShape( aRefLayer, FLASHING::DEFAULT, aConstraintType );
120
121 wxCHECK2_MSG( shape, return, wxT( "Item does not have a valid shape for this layer" ) );
122
123 if( shape->HasIndexableSubshapes() )
124 shape->GetIndexableSubshapes( subshapes );
125 else
126 subshapes.push_back( shape.get() );
127
128 for( const SHAPE* subshape : subshapes )
129 {
130 if( dynamic_cast<const SHAPE_NULL*>( subshape ) )
131 continue;
132
133 BOX2I bbox = subshape->BBox();
134
135 bbox.Inflate( aWorstClearance );
136
137 const int mmin[2] = { bbox.GetX(), bbox.GetY() };
138 const int mmax[2] = { bbox.GetRight(), bbox.GetBottom() };
139 ITEM_WITH_SHAPE* itemShape = new ITEM_WITH_SHAPE( parent, subshape, shape );
140
141 m_owned.push_back( itemShape );
142 m_builders[aTargetLayer].Add( mmin, mmax, itemShape );
143 recordPadding( aTargetLayer, aWorstClearance );
144 m_count++;
145 }
146
147 if( aItem->Type() == PCB_PAD_T && aItem->HasHole() )
148 {
149 std::shared_ptr<SHAPE_SEGMENT> hole = aItem->GetEffectiveHoleShape();
150 BOX2I bbox = hole->BBox();
151
152 bbox.Inflate( aWorstClearance );
153
154 const int mmin[2] = { bbox.GetX(), bbox.GetY() };
155 const int mmax[2] = { bbox.GetRight(), bbox.GetBottom() };
156 ITEM_WITH_SHAPE* itemShape = new ITEM_WITH_SHAPE( parent, hole, shape );
157
158 m_owned.push_back( itemShape );
159 m_builders[aTargetLayer].Add( mmin, mmax, itemShape );
160 recordPadding( aTargetLayer, aWorstClearance );
161 m_count++;
162 }
163 }
164
169 void Build()
170 {
171 for( auto& [layer, builder] : m_builders )
172 m_tree[layer] = builder.Build();
173
174 m_builders.clear();
175 }
176
180 void clear()
181 {
182 for( ITEM_WITH_SHAPE* p : m_owned )
183 delete p;
184
185 m_owned.clear();
186 m_tree.clear();
187 m_builders.clear();
188 m_minPadding.clear();
189 m_count = 0;
190 }
191
192 bool CheckColliding( SHAPE* aRefShape, PCB_LAYER_ID aTargetLayer, int aClearance = 0,
193 std::function<bool( BOARD_ITEM*)> aFilter = nullptr ) const
194 {
195 BOX2I box = aRefShape->BBox();
196 box.Inflate( aClearance );
197
198 int min[2] = { box.GetX(), box.GetY() };
199 int max[2] = { box.GetRight(), box.GetBottom() };
200
201 int count = 0;
202
203 auto visit =
204 [&] ( ITEM_WITH_SHAPE* aItem ) -> bool
205 {
206 if( !aFilter || aFilter( aItem->parent ) )
207 {
208 int actual;
209
210 if( aRefShape->Collide( aItem->shape, aClearance, &actual ) )
211 {
212 count++;
213 return false;
214 }
215 }
216
217 return true;
218 };
219
220 if( auto it = m_tree.find( aTargetLayer ); it != m_tree.end() )
221 it->second.Search( min, max, visit );
222
223 return count > 0;
224 }
225
235 bool CheckColliding( SHAPE* aRefShape, PCB_LAYER_ID aTargetLayer, int aMaxClearance,
236 const std::function<bool( BOARD_ITEM*, int* )>& aClearanceResolver ) const
237 {
238 BOX2I box = aRefShape->BBox();
239 box.Inflate( aMaxClearance );
240
241 int min[2] = { box.GetX(), box.GetY() };
242 int max[2] = { box.GetRight(), box.GetBottom() };
243
244 bool collision = false;
245
246 // Compound and triangulated items are visited once per subshape, but the clearance is
247 // a property of the item.
248 std::unordered_map<BOARD_ITEM*, std::pair<bool, int>> resolved;
249
250 auto visit =
251 [&] ( ITEM_WITH_SHAPE* aItem ) -> bool
252 {
253 auto it = resolved.find( aItem->parent );
254
255 if( it == resolved.end() )
256 {
257 int clearance = 0;
258 bool test = aClearanceResolver( aItem->parent, &clearance );
259
260 it = resolved.emplace( aItem->parent,
261 std::make_pair( test, clearance ) ).first;
262 }
263
264 if( !it->second.first )
265 return true;
266
267 if( aRefShape->Collide( aItem->shape, it->second.second ) )
268 {
269 collision = true;
270 return false;
271 }
272
273 return true;
274 };
275
276 if( auto it = m_tree.find( aTargetLayer ); it != m_tree.end() )
277 it->second.Search( min, max, visit );
278
279 return collision;
280 }
281
287 int QueryColliding( BOARD_ITEM* aRefItem, PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer,
288 std::function<bool( BOARD_ITEM* )> aFilter = nullptr,
289 std::function<bool( BOARD_ITEM* )> aVisitor = nullptr,
290 int aClearance = 0 ) const
291 {
292 // keep track of BOARD_ITEMs that have already been found to collide (some items might
293 // be built of COMPOUND/triangulated shapes and a single subshape collision means we have
294 // a hit)
295 std::unordered_set<BOARD_ITEM*> collidingCompounds;
296
297 // keep track of results of client filter so we don't ask more than once for compound
298 // shapes
299 std::unordered_map<BOARD_ITEM*, bool> filterResults;
300
301 BOX2I box = aRefItem->GetBoundingBox();
302 box.Inflate( aClearance );
303
304 int min[2] = { box.GetX(), box.GetY() };
305 int max[2] = { box.GetRight(), box.GetBottom() };
306
307 std::shared_ptr<SHAPE> refShape = aRefItem->GetEffectiveShape( aRefLayer );
308
309 int count = 0;
310
311 auto visit =
312 [&]( ITEM_WITH_SHAPE* aItem ) -> bool
313 {
314 if( aItem->parent == aRefItem )
315 return true;
316
317 if( collidingCompounds.find( aItem->parent ) != collidingCompounds.end() )
318 return true;
319
320 bool filtered;
321 auto it = filterResults.find( aItem->parent );
322
323 if( it == filterResults.end() )
324 {
325 filtered = aFilter && !aFilter( aItem->parent );
326 filterResults[ aItem->parent ] = filtered;
327 }
328 else
329 {
330 filtered = it->second;
331 }
332
333 if( filtered )
334 return true;
335
336 wxCHECK( aItem->shape, false );
337
338 if( refShape->Collide( aItem->shape, aClearance ) )
339 {
340 collidingCompounds.insert( aItem->parent );
341 count++;
342
343 if( aVisitor )
344 return aVisitor( aItem->parent );
345 }
346
347 return true;
348 };
349
350 if( auto it = m_tree.find( aTargetLayer ); it != m_tree.end() )
351 it->second.Search( min, max, visit );
352
353 return count;
354 }
355
367 BOARD_ITEM* aRefItem, const std::shared_ptr<SHAPE>& aRefShape,
368 PCB_LAYER_ID aTargetLayer, std::function<bool( BOARD_ITEM* )> aFilter,
369 std::function<bool( BOARD_ITEM*, const std::shared_ptr<SHAPE>& )> aVisitor,
370 int aClearance = 0, bool aUsePaddingCredit = false ) const
371 {
372 // PAD::GetEffectiveShape() returns null when a layer has no cached shape
373 wxCHECK( aRefShape, 0 );
374
375 std::unordered_set<BOARD_ITEM*> collidingCompounds;
376 std::unordered_map<BOARD_ITEM*, bool> filterResults;
377 BOX2I box = aRefItem->GetBoundingBox();
378 int inflation = aClearance;
379
380 if( aUsePaddingCredit && aClearance >= 0 )
381 {
382 // Checked before the box grows, because the credit can leave inflation at 0. A
383 // reference whose bounds do not contain its own shape would shrink the query past a
384 // real candidate and silently drop a clearance violation, so it pays full inflation
385 // instead of getting a wrong answer in a release build
386 bool contained = box.Contains( aRefShape->BBox() );
387
388 wxASSERT_MSG( contained, wxT( "Padding credit needs the item bbox to contain its own shape" ) );
389
390 auto paddingIt = m_minPadding.find( aTargetLayer );
391
392 if( contained && paddingIt != m_minPadding.end() && paddingIt->second >= 0 )
393 inflation = std::max( 0, aClearance - paddingIt->second );
394 }
395
396 box.Inflate( inflation );
397
398 int min[2] = { box.GetX(), box.GetY() };
399 int max[2] = { box.GetRight(), box.GetBottom() };
400 int count = 0;
401
402 auto visit =
403 [&]( ITEM_WITH_SHAPE* aItem ) -> bool
404 {
405 if( aItem->parent == aRefItem
406 || collidingCompounds.find( aItem->parent ) != collidingCompounds.end() )
407 {
408 return true;
409 }
410
411 auto [filterIt, inserted] = filterResults.emplace( aItem->parent, false );
412
413 if( inserted )
414 filterIt->second = aFilter && !aFilter( aItem->parent );
415
416 if( filterIt->second )
417 return true;
418
419 wxCHECK( aItem->shape, false );
420
421 if( aRefShape->Collide( aItem->shape, aClearance ) )
422 {
423 collidingCompounds.insert( aItem->parent );
424 count++;
425
426 if( aVisitor )
427 return aVisitor( aItem->parent, aItem->parentShape );
428 }
429
430 return true;
431 };
432
433 if( auto it = m_tree.find( aTargetLayer ); it != m_tree.end() )
434 it->second.Search( min, max, visit );
435
436 return count;
437 }
438
445 bool QueryColliding( const BOX2I& aBox, SHAPE* aRefShape, PCB_LAYER_ID aLayer, int aClearance,
446 int* aActual, VECTOR2I* aPos ) const
447 {
448 BOX2I bbox = aBox;
449 bbox.Inflate( aClearance );
450
451 int min[2] = { bbox.GetX(), bbox.GetY() };
452 int max[2] = { bbox.GetRight(), bbox.GetBottom() };
453
454 bool collision = false;
455 int actual = INT_MAX;
456 VECTOR2I pos;
457
458 auto visit =
459 [&]( ITEM_WITH_SHAPE* aItem ) -> bool
460 {
461 int curActual;
462 VECTOR2I curPos;
463
464 if( aRefShape->Collide( aItem->shape, aClearance, &curActual, &curPos ) )
465 {
466 collision = true;
467
468 if( curActual < actual )
469 {
470 actual = curActual;
471 pos = curPos;
472 }
473
474 // Stop looking after we have a true collision
475 if( actual <= 0 )
476 return false;
477 }
478
479 return true;
480 };
481
482 if( auto it = m_tree.find( aLayer ); it != m_tree.end() )
483 it->second.Search( min, max, visit );
484
485 if( collision )
486 {
487 if( aActual )
488 *aActual = std::max( 0, actual );
489
490 if( aPos )
491 *aPos = pos;
492
493 return true;
494 }
495
496 return false;
497 }
498
502 bool QueryColliding( const BOX2I& aBox, SHAPE* aRefShape, PCB_LAYER_ID aLayer ) const
503 {
504 SHAPE_POLY_SET* poly = dynamic_cast<SHAPE_POLY_SET*>( aRefShape );
505
506 int min[2] = { aBox.GetX(), aBox.GetY() };
507 int max[2] = { aBox.GetRight(), aBox.GetBottom() };
508 bool collision = false;
509
510 // Special case the polygon case. Otherwise we'll call its Collide() method which will
511 // triangulate it as well and then do triangle/triangle collisions. This ends up being
512 // *much* slower than 3 segment Collide()s and a PointInside().
513 auto polyVisitor =
514 [&]( ITEM_WITH_SHAPE* aItem ) -> bool
515 {
516 const SHAPE* shape = aItem->shape;
517
518 // There are certain degenerate cases that result in empty zone fills, which
519 // will be represented in the rtree with only a root (and no triangles).
520 // https://gitlab.com/kicad/code/kicad/-/issues/18600
521 if( shape->Type() != SH_POLY_SET_TRIANGLE )
522 return true;
523
524 auto tri = static_cast<const SHAPE_POLY_SET::TRIANGULATED_POLYGON::TRI*>( shape );
525
526 const SHAPE_LINE_CHAIN& outline = poly->Outline( 0 );
527
528 for( int ii = 0; ii < (int) tri->GetSegmentCount(); ++ii )
529 {
530 if( outline.Collide( tri->GetSegment( ii ) ) )
531 {
532 collision = true;
533 return false;
534 }
535 }
536
537 // Also must check for poly being completely inside the triangle
538 if( tri->PointInside( outline.CPoint( 0 ) ) )
539 {
540 collision = true;
541 return false;
542 }
543
544 return true;
545 };
546
547 auto visitor =
548 [&]( ITEM_WITH_SHAPE* aItem ) -> bool
549 {
550 if( aRefShape->Collide( aItem->shape, 0 ) )
551 {
552 collision = true;
553 return false;
554 }
555
556 return true;
557 };
558
559 auto it = m_tree.find( aLayer );
560
561 if( it == m_tree.end() )
562 return false;
563
564 if( poly && poly->OutlineCount() == 1 && poly->HoleCount( 0 ) == 0 )
565 it->second.Search( min, max, polyVisitor );
566 else
567 it->second.Search( min, max, visitor );
568
569 return collision;
570 }
571
580 std::unordered_set<BOARD_ITEM*> GetObjectsAt( const VECTOR2I& aPt, PCB_LAYER_ID aLayer,
581 int aClearance = 0 )
582 {
583 std::unordered_set<BOARD_ITEM*> retval;
584 int min[2] = { aPt.x - aClearance, aPt.y - aClearance };
585 int max[2] = { aPt.x + aClearance, aPt.y + aClearance };
586
587 auto visitor =
588 [&]( ITEM_WITH_SHAPE* aItem ) -> bool
589 {
590 retval.insert( aItem->parent );
591 return true;
592 };
593
594 auto it = m_tree.find( aLayer );
595
596 if( it != m_tree.end() )
597 it->second.Search( min, max, visitor );
598
599 return retval;
600 }
601
602 typedef std::pair<PCB_LAYER_ID, PCB_LAYER_ID> LAYER_PAIR;
603
605 {
607 layerPair( aPair ),
608 refItem( aRef ),
609 testItem( aTest )
610 { };
611
615 };
616
617 int QueryCollidingPairs( DRC_RTREE* aRefTree, std::vector<LAYER_PAIR> aLayerPairs,
618 std::function<bool( const LAYER_PAIR&, ITEM_WITH_SHAPE*,
619 ITEM_WITH_SHAPE*, bool* aCollision )> aVisitor,
620 int aMaxClearance,
621 std::function<bool(int, int )> aProgressReporter ) const
622 {
623 std::vector<PAIR_INFO> pairsToVisit;
624
625 for( LAYER_PAIR& layerPair : aLayerPairs )
626 {
627 const PCB_LAYER_ID refLayer = layerPair.first;
628 const PCB_LAYER_ID targetLayer = layerPair.second;
629
630 for( ITEM_WITH_SHAPE* refItem : aRefTree->OnLayer( refLayer ) )
631 {
632 BOX2I box = refItem->shape->BBox();
633 box.Inflate( aMaxClearance );
634
635 int min[2] = { box.GetX(), box.GetY() };
636 int max[2] = { box.GetRight(), box.GetBottom() };
637
638 auto visit =
639 [&]( ITEM_WITH_SHAPE* aItemToTest ) -> bool
640 {
641 // don't collide items against themselves
642 if( aItemToTest->parent == refItem->parent )
643 return true;
644
645 pairsToVisit.emplace_back( layerPair, refItem, aItemToTest );
646 return true;
647 };
648
649 auto it = m_tree.find( targetLayer );
650
651 if( it != m_tree.end() )
652 it->second.Search( min, max, visit );
653 };
654 }
655
656 // keep track of BOARD_ITEMs pairs that have been already found to collide (some items
657 // might be build of COMPOUND/triangulated shapes and a single subshape collision
658 // means we have a hit)
659 std::unordered_map<PTR_PTR_CACHE_KEY, int> collidingCompounds;
660
661 int progress = 0;
662 int count = pairsToVisit.size();
663
664 for( const PAIR_INFO& pair : pairsToVisit )
665 {
666 if( !aProgressReporter( progress++, count ) )
667 break;
668
669 BOARD_ITEM* a = pair.refItem->parent;
670 BOARD_ITEM* b = pair.testItem->parent;
671
672 // store canonical order so we don't collide in both directions (a:b and b:a)
673 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
674 std::swap( a, b );
675
676 // don't report multiple collisions for compound or triangulated shapes
677 if( collidingCompounds.count( { a, b } ) )
678 continue;
679
680 bool collisionDetected = false;
681
682 if( !aVisitor( pair.layerPair, pair.refItem, pair.testItem, &collisionDetected ) )
683 break;
684
685 if( collisionDetected )
686 collidingCompounds[ { a, b } ] = 1;
687 }
688
689 return 0;
690 }
691
697 size_t size() const
698 {
699 return m_count;
700 }
701
702 bool empty() const
703 {
704 return m_count == 0;
705 }
706
716 {
717 DRC_LAYER() = default;
718
719 DRC_LAYER( const drc_rtree& aTree )
720 {
721 for( ITEM_WITH_SHAPE* item : aTree )
722 m_items.push_back( item );
723 }
724
725 DRC_LAYER( const drc_rtree& aTree, const BOX2I& aRect )
726 {
727 int min[2] = { aRect.GetX(), aRect.GetY() };
728 int max[2] = { aRect.GetRight(), aRect.GetBottom() };
729
730 auto collector = [this]( ITEM_WITH_SHAPE* aItem ) -> bool
731 {
732 m_items.push_back( aItem );
733 return true;
734 };
735
736 aTree.Search( min, max, collector );
737 }
738
739 std::vector<ITEM_WITH_SHAPE*> m_items;
740
741 std::vector<ITEM_WITH_SHAPE*>::iterator begin() { return m_items.begin(); }
742 std::vector<ITEM_WITH_SHAPE*>::iterator end() { return m_items.end(); }
743 };
744
746 {
747 auto it = m_tree.find( aLayer );
748 return it == m_tree.end() ? DRC_LAYER() : DRC_LAYER( it->second );
749 }
750
751 DRC_LAYER Overlapping( PCB_LAYER_ID aLayer, const VECTOR2I& aPoint, int aAccuracy = 0 ) const
752 {
753 BOX2I rect( aPoint, VECTOR2I( 0, 0 ) );
754 rect.Inflate( aAccuracy );
755 auto it = m_tree.find( aLayer );
756 return it == m_tree.end() ? DRC_LAYER() : DRC_LAYER( it->second, rect );
757 }
758
759 DRC_LAYER Overlapping( PCB_LAYER_ID aLayer, const BOX2I& aRect ) const
760 {
761 auto it = m_tree.find( aLayer );
762 return it == m_tree.end() ? DRC_LAYER() : DRC_LAYER( it->second, aRect );
763 }
764
765
766private:
767 void recordPadding( PCB_LAYER_ID aLayer, int aPadding )
768 {
769 auto [it, inserted] = m_minPadding.emplace( aLayer, aPadding );
770
771 if( !inserted )
772 it->second = std::min( it->second, aPadding );
773 }
774
775 std::map<int, drc_rtree> m_tree;
776 std::map<int, drc_rtree_builder> m_builders;
777 std::map<int, int> m_minPadding;
778 std::vector<ITEM_WITH_SHAPE*> m_owned;
779 size_t m_count = 0;
780};
781
782
783#endif /* DRC_RTREE_H_ */
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 std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const
BOARD_ITEM_CONTAINER * GetParent() const
Definition board_item.h:266
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.
virtual bool HasHole() const
Definition board_item.h:207
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 coord_type GetY() const
Definition box2.h:205
constexpr coord_type GetX() const
Definition box2.h:204
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:165
constexpr coord_type GetRight() const
Definition box2.h:214
constexpr coord_type GetBottom() const
Definition box2.h:219
std::map< int, int > m_minPadding
Definition drc_rtree.h:777
DRC_LAYER OnLayer(PCB_LAYER_ID aLayer) const
Definition drc_rtree.h:745
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
bool CheckColliding(SHAPE *aRefShape, PCB_LAYER_ID aTargetLayer, int aMaxClearance, const std::function< bool(BOARD_ITEM *, int *)> &aClearanceResolver) const
As CheckColliding(), but the clearance is resolved per item hit rather than once for the whole query,...
Definition drc_rtree.h:235
void recordPadding(PCB_LAYER_ID aLayer, int aPadding)
Definition drc_rtree.h:767
size_t size() const
Return the number of items in the tree.
Definition drc_rtree.h:697
bool empty() const
Definition drc_rtree.h:702
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
typename drc_rtree::Builder drc_rtree_builder
Definition drc_rtree.h:76
bool CheckColliding(SHAPE *aRefShape, PCB_LAYER_ID aTargetLayer, int aClearance=0, std::function< bool(BOARD_ITEM *)> aFilter=nullptr) const
Definition drc_rtree.h:192
DRC_LAYER Overlapping(PCB_LAYER_ID aLayer, const BOX2I &aRect) const
Definition drc_rtree.h:759
KIRTREE::PACKED_RTREE< ITEM_WITH_SHAPE *, int, 2 > drc_rtree
Definition drc_rtree.h:75
std::unordered_set< BOARD_ITEM * > GetObjectsAt(const VECTOR2I &aPt, PCB_LAYER_ID aLayer, int aClearance=0)
Get the BOARD_ITEM objects that overlap the specified point/layer.
Definition drc_rtree.h:580
bool QueryColliding(const BOX2I &aBox, SHAPE *aRefShape, PCB_LAYER_ID aLayer) const
Quicker version of above that just reports a raw yes/no.
Definition drc_rtree.h:502
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
std::pair< PCB_LAYER_ID, PCB_LAYER_ID > LAYER_PAIR
Definition drc_rtree.h:602
size_t m_count
Definition drc_rtree.h:779
std::map< int, drc_rtree_builder > m_builders
Definition drc_rtree.h:776
DRC_LAYER Overlapping(PCB_LAYER_ID aLayer, const VECTOR2I &aPoint, int aAccuracy=0) const
Definition drc_rtree.h:751
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:617
std::vector< ITEM_WITH_SHAPE * > m_owned
Definition drc_rtree.h:778
void Build()
Finalize all pending inserts by bulk-building packed R-trees from the staged items.
Definition drc_rtree.h:169
bool QueryColliding(const BOX2I &aBox, SHAPE *aRefShape, PCB_LAYER_ID aLayer, int aClearance, int *aActual, VECTOR2I *aPos) const
This one is for tessellated items.
Definition drc_rtree.h:445
void Insert(BOARD_ITEM *aItem, PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer, DRC_CONSTRAINT_T aConstraintType, int aWorstClearance, bool aAtomicTables=false)
Insert an item into the tree on a particular layer with a worst clearance.
Definition drc_rtree.h:104
std::map< int, drc_rtree > m_tree
Definition drc_rtree.h:775
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:270
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
virtual bool IsVisible() const
Definition eda_text.h:226
Static (immutable) packed R-tree built via Hilbert-curve bulk loading.
int Search(const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], VISITOR &aVisitor) const
Search for all items whose bounding boxes overlap the query rectangle.
SHAPE_TYPE Type() const
Return the type of the shape.
Definition shape.h:96
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if point aP lies closer to us than aClearance.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
Represent a set of closed polygons.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int OutlineCount() const
Return the number of outlines in the set.
An abstract shape on 2D plane.
Definition shape.h:124
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const
Check if the boundary of shape (this) lies closer to the point aP than aClearance,...
Definition shape.h:181
virtual const BOX2I BBox(int aClearance=0) const =0
Compute a bounding box of the shape, with a margin of aClearance a collision.
DRC_CONSTRAINT_T
Definition drc_rule.h:49
@ DEFAULT
Flashing follows connectivity.
Definition layer_ids.h:181
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ UNDEFINED_LAYER
Definition layer_ids.h:57
STL namespace.
@ SH_POLY_SET_TRIANGLE
a single triangle belonging to a POLY_SET triangulation
Definition shape.h:52
The DRC_LAYER struct provides a layer-specific auto-range iterator to the RTree.
Definition drc_rtree.h:716
DRC_LAYER(const drc_rtree &aTree, const BOX2I &aRect)
Definition drc_rtree.h:725
DRC_LAYER(const drc_rtree &aTree)
Definition drc_rtree.h:719
std::vector< ITEM_WITH_SHAPE * >::iterator begin()
Definition drc_rtree.h:741
std::vector< ITEM_WITH_SHAPE * > m_items
Definition drc_rtree.h:739
std::vector< ITEM_WITH_SHAPE * >::iterator end()
Definition drc_rtree.h:742
std::shared_ptr< SHAPE > parentShape
Never null; Insert() only builds these from a shape wxCHECK2_MSG has already validated.
Definition drc_rtree.h:71
ITEM_WITH_SHAPE(BOARD_ITEM *aParent, const std::shared_ptr< SHAPE > &aShape, std::shared_ptr< SHAPE > aParentShape)
Definition drc_rtree.h:58
ITEM_WITH_SHAPE(BOARD_ITEM *aParent, const SHAPE *aShape, std::shared_ptr< SHAPE > aParentShape)
Definition drc_rtree.h:50
std::shared_ptr< SHAPE > shapeStorage
Definition drc_rtree.h:68
ITEM_WITH_SHAPE * refItem
Definition drc_rtree.h:613
PAIR_INFO(LAYER_PAIR aPair, ITEM_WITH_SHAPE *aRef, ITEM_WITH_SHAPE *aTest)
Definition drc_rtree.h:606
ITEM_WITH_SHAPE * testItem
Definition drc_rtree.h:614
LAYER_PAIR layerPair
Definition drc_rtree.h:612
int clearance
int actual
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:82
@ 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
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708