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 <memory>
27#include <unordered_set>
28#include <set>
29#include <vector>
30
32#include <geometry/shape.h>
34#include <math/vector2d.h>
35#include "geometry/shape_null.h"
36#include "board.h"
37
38#define ATOMIC_TABLES true
39
45{
46public:
48 {
49 ITEM_WITH_SHAPE( BOARD_ITEM *aParent, const SHAPE* aShape,
50 std::shared_ptr<SHAPE> aParentShape = nullptr ) :
51 parent( aParent ),
52 shape( aShape ),
53 shapeStorage( nullptr ),
54 parentShape( std::move( aParentShape ) )
55 {};
56
57 ITEM_WITH_SHAPE( BOARD_ITEM *aParent, const std::shared_ptr<SHAPE>& aShape,
58 std::shared_ptr<SHAPE> aParentShape = nullptr ) :
59 parent( aParent ),
60 shape( aShape.get() ),
61 shapeStorage( aShape ),
62 parentShape( std::move( aParentShape ) )
63 {};
64
66 const SHAPE* shape;
67 std::shared_ptr<SHAPE> shapeStorage;
68 std::shared_ptr<SHAPE> parentShape;
69 };
70
71private:
73 using drc_rtree_builder = typename drc_rtree::Builder;
74
75public:
77 {
78 m_count = 0;
79 }
80
82 {
83 for( ITEM_WITH_SHAPE* p : m_owned )
84 delete p;
85 }
86
91 void Insert( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, DRC_CONSTRAINT_T aConstraintType,
92 int aWorstClearance = 0, bool aAtomicTables = false )
93 {
94 Insert( aItem, aLayer, aLayer, aConstraintType, aWorstClearance, aAtomicTables );
95 }
96
101 void Insert( BOARD_ITEM* aItem, PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer,
102 DRC_CONSTRAINT_T aConstraintType, int aWorstClearance, bool aAtomicTables = false )
103 {
104 wxCHECK( aTargetLayer != UNDEFINED_LAYER, /* void */ );
105 wxCHECK_MSG( !m_tree.count( aTargetLayer ), /* void */, wxT( "Insert after Build() is silently wrong" ) );
106
107 if( aItem->Type() == PCB_FIELD_T && !static_cast<PCB_FIELD*>( aItem )->IsVisible() )
108 return;
109
110 BOARD_ITEM* parent = aItem;
111
112 if( aAtomicTables && aItem->Type() == PCB_TABLECELL_T )
113 parent = aItem->GetParent();
114
115 std::vector<const SHAPE*> subshapes;
116 std::shared_ptr<SHAPE> shape = aItem->GetEffectiveShape( aRefLayer, FLASHING::DEFAULT, aConstraintType );
117
118 wxCHECK2_MSG( shape, return, wxT( "Item does not have a valid shape for this layer" ) );
119
120 if( shape->HasIndexableSubshapes() )
121 shape->GetIndexableSubshapes( subshapes );
122 else
123 subshapes.push_back( shape.get() );
124
125 for( const SHAPE* subshape : subshapes )
126 {
127 if( dynamic_cast<const SHAPE_NULL*>( subshape ) )
128 continue;
129
130 BOX2I bbox = subshape->BBox();
131
132 bbox.Inflate( aWorstClearance );
133
134 const int mmin[2] = { bbox.GetX(), bbox.GetY() };
135 const int mmax[2] = { bbox.GetRight(), bbox.GetBottom() };
136 ITEM_WITH_SHAPE* itemShape = new ITEM_WITH_SHAPE( parent, subshape, shape );
137
138 m_owned.push_back( itemShape );
139 m_builders[aTargetLayer].Add( mmin, mmax, itemShape );
140 m_count++;
141 }
142
143 if( aItem->Type() == PCB_PAD_T && aItem->HasHole() )
144 {
145 std::shared_ptr<SHAPE_SEGMENT> hole = aItem->GetEffectiveHoleShape();
146 BOX2I bbox = hole->BBox();
147
148 bbox.Inflate( aWorstClearance );
149
150 const int mmin[2] = { bbox.GetX(), bbox.GetY() };
151 const int mmax[2] = { bbox.GetRight(), bbox.GetBottom() };
152 ITEM_WITH_SHAPE* itemShape = new ITEM_WITH_SHAPE( parent, hole, shape );
153
154 m_owned.push_back( itemShape );
155 m_builders[aTargetLayer].Add( mmin, mmax, itemShape );
156 m_count++;
157 }
158 }
159
164 void Build()
165 {
166 for( auto& [layer, builder] : m_builders )
167 m_tree[layer] = builder.Build();
168
169 m_builders.clear();
170 }
171
175 void clear()
176 {
177 for( ITEM_WITH_SHAPE* p : m_owned )
178 delete p;
179
180 m_owned.clear();
181 m_tree.clear();
182 m_builders.clear();
183 m_count = 0;
184 }
185
186 bool CheckColliding( SHAPE* aRefShape, PCB_LAYER_ID aTargetLayer, int aClearance = 0,
187 std::function<bool( BOARD_ITEM*)> aFilter = nullptr ) const
188 {
189 BOX2I box = aRefShape->BBox();
190 box.Inflate( aClearance );
191
192 int min[2] = { box.GetX(), box.GetY() };
193 int max[2] = { box.GetRight(), box.GetBottom() };
194
195 int count = 0;
196
197 auto visit =
198 [&] ( ITEM_WITH_SHAPE* aItem ) -> bool
199 {
200 if( !aFilter || aFilter( aItem->parent ) )
201 {
202 int actual;
203
204 if( aRefShape->Collide( aItem->shape, aClearance, &actual ) )
205 {
206 count++;
207 return false;
208 }
209 }
210
211 return true;
212 };
213
214 if( auto it = m_tree.find( aTargetLayer ); it != m_tree.end() )
215 it->second.Search( min, max, visit );
216
217 return count > 0;
218 }
219
225 bool CheckColliding( SHAPE* aRefShape, PCB_LAYER_ID aTargetLayer, int aMaxClearance,
226 const std::function<bool( BOARD_ITEM*, int* )>& aClearanceResolver ) const
227 {
228 BOX2I box = aRefShape->BBox();
229 box.Inflate( aMaxClearance );
230
231 int min[2] = { box.GetX(), box.GetY() };
232 int max[2] = { box.GetRight(), box.GetBottom() };
233
234 bool collision = false;
235
236 // Compound and triangulated items are visited once per subshape, but the clearance is
237 // a property of the item.
238 std::unordered_map<BOARD_ITEM*, std::pair<bool, int>> resolved;
239
240 auto visit =
241 [&] ( ITEM_WITH_SHAPE* aItem ) -> bool
242 {
243 auto it = resolved.find( aItem->parent );
244
245 if( it == resolved.end() )
246 {
247 int clearance = 0;
248 bool test = aClearanceResolver( aItem->parent, &clearance );
249
250 it = resolved.emplace( aItem->parent,
251 std::make_pair( test, clearance ) ).first;
252 }
253
254 if( !it->second.first )
255 return true;
256
257 if( aRefShape->Collide( aItem->shape, it->second.second ) )
258 {
259 collision = true;
260 return false;
261 }
262
263 return true;
264 };
265
266 if( auto it = m_tree.find( aTargetLayer ); it != m_tree.end() )
267 it->second.Search( min, max, visit );
268
269 return collision;
270 }
271
277 int QueryColliding( BOARD_ITEM* aRefItem, PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer,
278 std::function<bool( BOARD_ITEM* )> aFilter = nullptr,
279 std::function<bool( BOARD_ITEM* )> aVisitor = nullptr,
280 int aClearance = 0 ) const
281 {
282 // keep track of BOARD_ITEMs that have already been found to collide (some items might
283 // be built of COMPOUND/triangulated shapes and a single subshape collision means we have
284 // a hit)
285 std::unordered_set<BOARD_ITEM*> collidingCompounds;
286
287 // keep track of results of client filter so we don't ask more than once for compound
288 // shapes
289 std::unordered_map<BOARD_ITEM*, bool> filterResults;
290
291 BOX2I box = aRefItem->GetBoundingBox();
292 box.Inflate( aClearance );
293
294 int min[2] = { box.GetX(), box.GetY() };
295 int max[2] = { box.GetRight(), box.GetBottom() };
296
297 std::shared_ptr<SHAPE> refShape = aRefItem->GetEffectiveShape( aRefLayer );
298
299 int count = 0;
300
301 auto visit =
302 [&]( ITEM_WITH_SHAPE* aItem ) -> bool
303 {
304 if( aItem->parent == aRefItem )
305 return true;
306
307 if( collidingCompounds.find( aItem->parent ) != collidingCompounds.end() )
308 return true;
309
310 bool filtered;
311 auto it = filterResults.find( aItem->parent );
312
313 if( it == filterResults.end() )
314 {
315 filtered = aFilter && !aFilter( aItem->parent );
316 filterResults[ aItem->parent ] = filtered;
317 }
318 else
319 {
320 filtered = it->second;
321 }
322
323 if( filtered )
324 return true;
325
326 wxCHECK( aItem->shape, false );
327
328 if( refShape->Collide( aItem->shape, aClearance ) )
329 {
330 collidingCompounds.insert( aItem->parent );
331 count++;
332
333 if( aVisitor )
334 return aVisitor( aItem->parent );
335 }
336
337 return true;
338 };
339
340 if( auto it = m_tree.find( aTargetLayer ); it != m_tree.end() )
341 it->second.Search( min, max, visit );
342
343 return count;
344 }
345
352 bool QueryColliding( const BOX2I& aBox, SHAPE* aRefShape, PCB_LAYER_ID aLayer, int aClearance,
353 int* aActual, VECTOR2I* aPos ) const
354 {
355 BOX2I bbox = aBox;
356 bbox.Inflate( aClearance );
357
358 int min[2] = { bbox.GetX(), bbox.GetY() };
359 int max[2] = { bbox.GetRight(), bbox.GetBottom() };
360
361 bool collision = false;
362 int actual = INT_MAX;
363 VECTOR2I pos;
364
365 auto visit =
366 [&]( ITEM_WITH_SHAPE* aItem ) -> bool
367 {
368 int curActual;
369 VECTOR2I curPos;
370
371 if( aRefShape->Collide( aItem->shape, aClearance, &curActual, &curPos ) )
372 {
373 collision = true;
374
375 if( curActual < actual )
376 {
377 actual = curActual;
378 pos = curPos;
379 }
380
381 // Stop looking after we have a true collision
382 if( actual <= 0 )
383 return false;
384 }
385
386 return true;
387 };
388
389 if( auto it = m_tree.find( aLayer ); it != m_tree.end() )
390 it->second.Search( min, max, visit );
391
392 if( collision )
393 {
394 if( aActual )
395 *aActual = std::max( 0, actual );
396
397 if( aPos )
398 *aPos = pos;
399
400 return true;
401 }
402
403 return false;
404 }
405
409 bool QueryColliding( const BOX2I& aBox, SHAPE* aRefShape, PCB_LAYER_ID aLayer ) const
410 {
411 SHAPE_POLY_SET* poly = dynamic_cast<SHAPE_POLY_SET*>( aRefShape );
412
413 int min[2] = { aBox.GetX(), aBox.GetY() };
414 int max[2] = { aBox.GetRight(), aBox.GetBottom() };
415 bool collision = false;
416
417 // Special case the polygon case. Otherwise we'll call its Collide() method which will
418 // triangulate it as well and then do triangle/triangle collisions. This ends up being
419 // *much* slower than 3 segment Collide()s and a PointInside().
420 auto polyVisitor =
421 [&]( ITEM_WITH_SHAPE* aItem ) -> bool
422 {
423 const SHAPE* shape = aItem->shape;
424
425 // There are certain degenerate cases that result in empty zone fills, which
426 // will be represented in the rtree with only a root (and no triangles).
427 // https://gitlab.com/kicad/code/kicad/-/issues/18600
428 if( shape->Type() != SH_POLY_SET_TRIANGLE )
429 return true;
430
431 auto tri = static_cast<const SHAPE_POLY_SET::TRIANGULATED_POLYGON::TRI*>( shape );
432
433 const SHAPE_LINE_CHAIN& outline = poly->Outline( 0 );
434
435 for( int ii = 0; ii < (int) tri->GetSegmentCount(); ++ii )
436 {
437 if( outline.Collide( tri->GetSegment( ii ) ) )
438 {
439 collision = true;
440 return false;
441 }
442 }
443
444 // Also must check for poly being completely inside the triangle
445 if( tri->PointInside( outline.CPoint( 0 ) ) )
446 {
447 collision = true;
448 return false;
449 }
450
451 return true;
452 };
453
454 auto visitor =
455 [&]( ITEM_WITH_SHAPE* aItem ) -> bool
456 {
457 if( aRefShape->Collide( aItem->shape, 0 ) )
458 {
459 collision = true;
460 return false;
461 }
462
463 return true;
464 };
465
466 auto it = m_tree.find( aLayer );
467
468 if( it == m_tree.end() )
469 return false;
470
471 if( poly && poly->OutlineCount() == 1 && poly->HoleCount( 0 ) == 0 )
472 it->second.Search( min, max, polyVisitor );
473 else
474 it->second.Search( min, max, visitor );
475
476 return collision;
477 }
478
485 std::unordered_set<BOARD_ITEM*> GetObjectsAt( const VECTOR2I& aPt, PCB_LAYER_ID aLayer,
486 int aClearance = 0 )
487 {
488 std::unordered_set<BOARD_ITEM*> retval;
489 int min[2] = { aPt.x - aClearance, aPt.y - aClearance };
490 int max[2] = { aPt.x + aClearance, aPt.y + aClearance };
491
492 auto visitor =
493 [&]( ITEM_WITH_SHAPE* aItem ) -> bool
494 {
495 retval.insert( aItem->parent );
496 return true;
497 };
498
499 auto it = m_tree.find( aLayer );
500
501 if( it != m_tree.end() )
502 it->second.Search( min, max, visitor );
503
504 return retval;
505 }
506
507 typedef std::pair<PCB_LAYER_ID, PCB_LAYER_ID> LAYER_PAIR;
508
510 {
512 layerPair( aPair ),
513 refItem( aRef ),
514 testItem( aTest )
515 { };
516
520 };
521
522 int QueryCollidingPairs( DRC_RTREE* aRefTree, std::vector<LAYER_PAIR> aLayerPairs,
523 std::function<bool( const LAYER_PAIR&, ITEM_WITH_SHAPE*,
524 ITEM_WITH_SHAPE*, bool* aCollision )> aVisitor,
525 int aMaxClearance,
526 std::function<bool(int, int )> aProgressReporter ) const
527 {
528 std::vector<PAIR_INFO> pairsToVisit;
529
530 for( LAYER_PAIR& layerPair : aLayerPairs )
531 {
532 const PCB_LAYER_ID refLayer = layerPair.first;
533 const PCB_LAYER_ID targetLayer = layerPair.second;
534
535 for( ITEM_WITH_SHAPE* refItem : aRefTree->OnLayer( refLayer ) )
536 {
537 BOX2I box = refItem->shape->BBox();
538 box.Inflate( aMaxClearance );
539
540 int min[2] = { box.GetX(), box.GetY() };
541 int max[2] = { box.GetRight(), box.GetBottom() };
542
543 auto visit =
544 [&]( ITEM_WITH_SHAPE* aItemToTest ) -> bool
545 {
546 // don't collide items against themselves
547 if( aItemToTest->parent == refItem->parent )
548 return true;
549
550 pairsToVisit.emplace_back( layerPair, refItem, aItemToTest );
551 return true;
552 };
553
554 auto it = m_tree.find( targetLayer );
555
556 if( it != m_tree.end() )
557 it->second.Search( min, max, visit );
558 };
559 }
560
561 // keep track of BOARD_ITEMs pairs that have been already found to collide (some items
562 // might be build of COMPOUND/triangulated shapes and a single subshape collision
563 // means we have a hit)
564 std::unordered_map<PTR_PTR_CACHE_KEY, int> collidingCompounds;
565
566 int progress = 0;
567 int count = pairsToVisit.size();
568
569 for( const PAIR_INFO& pair : pairsToVisit )
570 {
571 if( !aProgressReporter( progress++, count ) )
572 break;
573
574 BOARD_ITEM* a = pair.refItem->parent;
575 BOARD_ITEM* b = pair.testItem->parent;
576
577 // store canonical order so we don't collide in both directions (a:b and b:a)
578 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
579 std::swap( a, b );
580
581 // don't report multiple collisions for compound or triangulated shapes
582 if( collidingCompounds.count( { a, b } ) )
583 continue;
584
585 bool collisionDetected = false;
586
587 if( !aVisitor( pair.layerPair, pair.refItem, pair.testItem, &collisionDetected ) )
588 break;
589
590 if( collisionDetected )
591 collidingCompounds[ { a, b } ] = 1;
592 }
593
594 return 0;
595 }
596
602 size_t size() const
603 {
604 return m_count;
605 }
606
607 bool empty() const
608 {
609 return m_count == 0;
610 }
611
621 {
622 DRC_LAYER() = default;
623
624 DRC_LAYER( const drc_rtree& aTree )
625 {
626 for( ITEM_WITH_SHAPE* item : aTree )
627 m_items.push_back( item );
628 }
629
630 DRC_LAYER( const drc_rtree& aTree, const BOX2I& aRect )
631 {
632 int min[2] = { aRect.GetX(), aRect.GetY() };
633 int max[2] = { aRect.GetRight(), aRect.GetBottom() };
634
635 auto collector = [this]( ITEM_WITH_SHAPE* aItem ) -> bool
636 {
637 m_items.push_back( aItem );
638 return true;
639 };
640
641 aTree.Search( min, max, collector );
642 }
643
644 std::vector<ITEM_WITH_SHAPE*> m_items;
645
646 std::vector<ITEM_WITH_SHAPE*>::iterator begin() { return m_items.begin(); }
647 std::vector<ITEM_WITH_SHAPE*>::iterator end() { return m_items.end(); }
648 };
649
651 {
652 auto it = m_tree.find( aLayer );
653 return it == m_tree.end() ? DRC_LAYER() : DRC_LAYER( it->second );
654 }
655
656 DRC_LAYER Overlapping( PCB_LAYER_ID aLayer, const VECTOR2I& aPoint, int aAccuracy = 0 ) const
657 {
658 BOX2I rect( aPoint, VECTOR2I( 0, 0 ) );
659 rect.Inflate( aAccuracy );
660 auto it = m_tree.find( aLayer );
661 return it == m_tree.end() ? DRC_LAYER() : DRC_LAYER( it->second, rect );
662 }
663
664 DRC_LAYER Overlapping( PCB_LAYER_ID aLayer, const BOX2I& aRect ) const
665 {
666 auto it = m_tree.find( aLayer );
667 return it == m_tree.end() ? DRC_LAYER() : DRC_LAYER( it->second, aRect );
668 }
669
670
671private:
672 std::map<int, drc_rtree> m_tree;
673 std::map<int, drc_rtree_builder> m_builders;
674 std::vector<ITEM_WITH_SHAPE*> m_owned;
675 size_t m_count = 0;
676};
677
678
679#endif /* DRC_RTREE_H_ */
BOX2< VECTOR2I > BOX2I
Definition box2.h:927
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 coord_type GetRight() const
Definition box2.h:214
constexpr coord_type GetBottom() const
Definition box2.h:219
DRC_LAYER OnLayer(PCB_LAYER_ID aLayer) const
Definition drc_rtree.h:650
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:91
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:225
size_t size() const
Return the number of items in the tree.
Definition drc_rtree.h:602
bool empty() const
Definition drc_rtree.h:607
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:277
typename drc_rtree::Builder drc_rtree_builder
Definition drc_rtree.h:73
bool CheckColliding(SHAPE *aRefShape, PCB_LAYER_ID aTargetLayer, int aClearance=0, std::function< bool(BOARD_ITEM *)> aFilter=nullptr) const
Definition drc_rtree.h:186
DRC_LAYER Overlapping(PCB_LAYER_ID aLayer, const BOX2I &aRect) const
Definition drc_rtree.h:664
KIRTREE::PACKED_RTREE< ITEM_WITH_SHAPE *, int, 2 > drc_rtree
Definition drc_rtree.h:72
std::unordered_set< BOARD_ITEM * > GetObjectsAt(const VECTOR2I &aPt, PCB_LAYER_ID aLayer, int aClearance=0)
Gets the BOARD_ITEMs that overlap the specified point/layer.
Definition drc_rtree.h:485
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:409
void clear()
Remove all items from the RTree.
Definition drc_rtree.h:175
std::pair< PCB_LAYER_ID, PCB_LAYER_ID > LAYER_PAIR
Definition drc_rtree.h:507
size_t m_count
Definition drc_rtree.h:675
std::map< int, drc_rtree_builder > m_builders
Definition drc_rtree.h:673
DRC_LAYER Overlapping(PCB_LAYER_ID aLayer, const VECTOR2I &aPoint, int aAccuracy=0) const
Definition drc_rtree.h:656
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:522
std::vector< ITEM_WITH_SHAPE * > m_owned
Definition drc_rtree.h:674
void Build()
Finalize all pending inserts by bulk-building packed R-trees from the staged items.
Definition drc_rtree.h:164
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:352
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:101
std::map< int, drc_rtree > m_tree
Definition drc_rtree.h:672
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:179
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:621
DRC_LAYER(const drc_rtree &aTree, const BOX2I &aRect)
Definition drc_rtree.h:630
DRC_LAYER(const drc_rtree &aTree)
Definition drc_rtree.h:624
std::vector< ITEM_WITH_SHAPE * >::iterator begin()
Definition drc_rtree.h:646
std::vector< ITEM_WITH_SHAPE * > m_items
Definition drc_rtree.h:644
std::vector< ITEM_WITH_SHAPE * >::iterator end()
Definition drc_rtree.h:647
ITEM_WITH_SHAPE(BOARD_ITEM *aParent, const SHAPE *aShape, std::shared_ptr< SHAPE > aParentShape=nullptr)
Definition drc_rtree.h:49
std::shared_ptr< SHAPE > parentShape
Definition drc_rtree.h:68
ITEM_WITH_SHAPE(BOARD_ITEM *aParent, const std::shared_ptr< SHAPE > &aShape, std::shared_ptr< SHAPE > aParentShape=nullptr)
Definition drc_rtree.h:57
std::shared_ptr< SHAPE > shapeStorage
Definition drc_rtree.h:67
ITEM_WITH_SHAPE * refItem
Definition drc_rtree.h:518
PAIR_INFO(LAYER_PAIR aPair, ITEM_WITH_SHAPE *aRef, ITEM_WITH_SHAPE *aTest)
Definition drc_rtree.h:511
ITEM_WITH_SHAPE * testItem
Definition drc_rtree.h:519
LAYER_PAIR layerPair
Definition drc_rtree.h:517
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:683