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, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-3.0.html
20 * or you may search the http://www.gnu.org website for the version 3 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#ifndef DRC_RTREE_H_
26#define DRC_RTREE_H_
27
28#include <board_item.h>
29#include <pcb_field.h>
30#include <memory>
31#include <unordered_set>
32#include <set>
33#include <vector>
34
35#include <geometry/rtree.h>
36#include <geometry/shape.h>
38#include <math/vector2d.h>
39#include "geometry/shape_null.h"
40#include "board.h"
41
42#define ATOMIC_TABLES true
43
49{
50public:
52 {
53 ITEM_WITH_SHAPE( BOARD_ITEM *aParent, const SHAPE* aShape,
54 std::shared_ptr<SHAPE> aParentShape = nullptr ) :
55 parent( aParent ),
56 shape( aShape ),
57 shapeStorage( nullptr ),
58 parentShape( std::move( aParentShape ) )
59 {};
60
61 ITEM_WITH_SHAPE( BOARD_ITEM *aParent, const std::shared_ptr<SHAPE>& aShape,
62 std::shared_ptr<SHAPE> aParentShape = nullptr ) :
63 parent( aParent ),
64 shape( aShape.get() ),
65 shapeStorage( aShape ),
66 parentShape( std::move( aParentShape ) )
67 {};
68
70 const SHAPE* shape;
71 std::shared_ptr<SHAPE> shapeStorage;
72 std::shared_ptr<SHAPE> parentShape;
73 };
74
75private:
76 using drc_rtree = RTree<ITEM_WITH_SHAPE*, int, 2, double>;
77
78public:
80 {
81 for( int layer : LSET::AllLayersMask() )
82 m_tree[layer] = new drc_rtree();
83
84 m_count = 0;
85 }
86
88 {
89 for( auto& [_, tree] : m_tree )
90 {
91 for( DRC_RTREE::ITEM_WITH_SHAPE* el : *tree )
92 delete el;
93
94 delete tree;
95 }
96 }
97
101 void Insert( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, int aWorstClearance = 0, bool aAtomicTables = false )
102 {
103 Insert( aItem, aLayer, aLayer, aWorstClearance, aAtomicTables );
104 }
105
110 void Insert( BOARD_ITEM* aItem, PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer,
111 int aWorstClearance, bool aAtomicTables = false )
112 {
113 wxCHECK( aTargetLayer != UNDEFINED_LAYER, /* void */ );
114
115 if( aItem->Type() == PCB_FIELD_T && !static_cast<PCB_FIELD*>( aItem )->IsVisible() )
116 return;
117
118 BOARD_ITEM* parent = aItem;
119
120 if( aAtomicTables && aItem->Type() == PCB_TABLECELL_T )
121 parent = aItem->GetParent();
122
123 std::vector<const SHAPE*> subshapes;
124 std::shared_ptr<SHAPE> shape = aItem->GetEffectiveShape( aRefLayer );
125
126 wxCHECK2_MSG( shape, return, wxT( "Item does not have a valid shape for this layer" ) );
127
128 if( shape->HasIndexableSubshapes() )
129 shape->GetIndexableSubshapes( subshapes );
130 else
131 subshapes.push_back( shape.get() );
132
133 for( const SHAPE* subshape : subshapes )
134 {
135 if( dynamic_cast<const SHAPE_NULL*>( subshape ) )
136 continue;
137
138 BOX2I bbox = subshape->BBox();
139
140 bbox.Inflate( aWorstClearance );
141
142 const int mmin[2] = { bbox.GetX(), bbox.GetY() };
143 const int mmax[2] = { bbox.GetRight(), bbox.GetBottom() };
144 ITEM_WITH_SHAPE* itemShape = new ITEM_WITH_SHAPE( parent, subshape, shape );
145
146 m_tree[aTargetLayer]->Insert( mmin, mmax, itemShape );
147 m_count++;
148 }
149
150 if( aItem->Type() == PCB_PAD_T && aItem->HasHole() )
151 {
152 std::shared_ptr<SHAPE_SEGMENT> hole = aItem->GetEffectiveHoleShape();
153 BOX2I bbox = hole->BBox();
154
155 bbox.Inflate( aWorstClearance );
156
157 const int mmin[2] = { bbox.GetX(), bbox.GetY() };
158 const int mmax[2] = { bbox.GetRight(), bbox.GetBottom() };
159 ITEM_WITH_SHAPE* itemShape = new ITEM_WITH_SHAPE( parent, hole, shape );
160
161 m_tree[aTargetLayer]->Insert( mmin, mmax, itemShape );
162 m_count++;
163 }
164 }
165
169 void clear()
170 {
171 for( auto& [_, tree] : m_tree )
172 {
173 for( ITEM_WITH_SHAPE* el : *tree )
174 delete el;
175
176 tree->RemoveAll();
177 }
178
179 m_count = 0;
180 }
181
182 bool CheckColliding( SHAPE* aRefShape, PCB_LAYER_ID aTargetLayer, int aClearance = 0,
183 std::function<bool( BOARD_ITEM*)> aFilter = nullptr ) const
184 {
185 BOX2I box = aRefShape->BBox();
186 box.Inflate( aClearance );
187
188 int min[2] = { box.GetX(), box.GetY() };
189 int max[2] = { box.GetRight(), box.GetBottom() };
190
191 int count = 0;
192
193 auto visit =
194 [&] ( ITEM_WITH_SHAPE* aItem ) -> bool
195 {
196 if( !aFilter || aFilter( aItem->parent ) )
197 {
198 int actual;
199
200 if( aRefShape->Collide( aItem->shape, aClearance, &actual ) )
201 {
202 count++;
203 return false;
204 }
205 }
206
207 return true;
208 };
209
210 if( auto it = m_tree.find( aTargetLayer ); it != m_tree.end() )
211 it->second->Search( min, max, visit );
212
213 return count > 0;
214 }
215
221 int QueryColliding( BOARD_ITEM* aRefItem, PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer,
222 std::function<bool( BOARD_ITEM* )> aFilter = nullptr,
223 std::function<bool( BOARD_ITEM* )> aVisitor = nullptr,
224 int aClearance = 0 ) const
225 {
226 // keep track of BOARD_ITEMs that have already been found to collide (some items might
227 // be built of COMPOUND/triangulated shapes and a single subshape collision means we have
228 // a hit)
229 std::unordered_set<BOARD_ITEM*> collidingCompounds;
230
231 // keep track of results of client filter so we don't ask more than once for compound
232 // shapes
233 std::unordered_map<BOARD_ITEM*, bool> filterResults;
234
235 BOX2I box = aRefItem->GetBoundingBox();
236 box.Inflate( aClearance );
237
238 int min[2] = { box.GetX(), box.GetY() };
239 int max[2] = { box.GetRight(), box.GetBottom() };
240
241 std::shared_ptr<SHAPE> refShape = aRefItem->GetEffectiveShape( aRefLayer );
242
243 int count = 0;
244
245 auto visit =
246 [&]( ITEM_WITH_SHAPE* aItem ) -> bool
247 {
248 if( aItem->parent == aRefItem )
249 return true;
250
251 if( collidingCompounds.find( aItem->parent ) != collidingCompounds.end() )
252 return true;
253
254 bool filtered;
255 auto it = filterResults.find( aItem->parent );
256
257 if( it == filterResults.end() )
258 {
259 filtered = aFilter && !aFilter( aItem->parent );
260 filterResults[ aItem->parent ] = filtered;
261 }
262 else
263 {
264 filtered = it->second;
265 }
266
267 if( filtered )
268 return true;
269
270 wxCHECK( aItem->shape, false );
271
272 if( refShape->Collide( aItem->shape, aClearance ) )
273 {
274 collidingCompounds.insert( aItem->parent );
275 count++;
276
277 if( aVisitor )
278 return aVisitor( aItem->parent );
279 }
280
281 return true;
282 };
283
284 if( auto it = m_tree.find( aTargetLayer ); it != m_tree.end() )
285 it->second->Search( min, max, visit );
286
287 return count;
288 }
289
296 bool QueryColliding( const BOX2I& aBox, SHAPE* aRefShape, PCB_LAYER_ID aLayer, int aClearance,
297 int* aActual, VECTOR2I* aPos ) const
298 {
299 BOX2I bbox = aBox;
300 bbox.Inflate( aClearance );
301
302 int min[2] = { bbox.GetX(), bbox.GetY() };
303 int max[2] = { bbox.GetRight(), bbox.GetBottom() };
304
305 bool collision = false;
306 int actual = INT_MAX;
307 VECTOR2I pos;
308
309 auto visit =
310 [&]( ITEM_WITH_SHAPE* aItem ) -> bool
311 {
312 int curActual;
313 VECTOR2I curPos;
314
315 if( aRefShape->Collide( aItem->shape, aClearance, &curActual, &curPos ) )
316 {
317 collision = true;
318
319 if( curActual < actual )
320 {
321 actual = curActual;
322 pos = curPos;
323 }
324
325 // Stop looking after we have a true collision
326 if( actual <= 0 )
327 return false;
328 }
329
330 return true;
331 };
332
333 if( auto it = m_tree.find( aLayer ); it != m_tree.end() )
334 it->second->Search( min, max, visit );
335
336 if( collision )
337 {
338 if( aActual )
339 *aActual = std::max( 0, actual );
340
341 if( aPos )
342 *aPos = pos;
343
344 return true;
345 }
346
347 return false;
348 }
349
353 bool QueryColliding( const BOX2I& aBox, SHAPE* aRefShape, PCB_LAYER_ID aLayer ) const
354 {
355 SHAPE_POLY_SET* poly = dynamic_cast<SHAPE_POLY_SET*>( aRefShape );
356
357 int min[2] = { aBox.GetX(), aBox.GetY() };
358 int max[2] = { aBox.GetRight(), aBox.GetBottom() };
359 bool collision = false;
360
361 // Special case the polygon case. Otherwise we'll call its Collide() method which will
362 // triangulate it as well and then do triangle/triangle collisions. This ends up being
363 // *much* slower than 3 segment Collide()s and a PointInside().
364 auto polyVisitor =
365 [&]( ITEM_WITH_SHAPE* aItem ) -> bool
366 {
367 const SHAPE* shape = aItem->shape;
368
369 // There are certain degenerate cases that result in empty zone fills, which
370 // will be represented in the rtree with only a root (and no triangles).
371 // https://gitlab.com/kicad/code/kicad/-/issues/18600
372 if( shape->Type() != SH_POLY_SET_TRIANGLE )
373 return true;
374
375 auto tri = static_cast<const SHAPE_POLY_SET::TRIANGULATED_POLYGON::TRI*>( shape );
376
377 const SHAPE_LINE_CHAIN& outline = poly->Outline( 0 );
378
379 for( int ii = 0; ii < (int) tri->GetSegmentCount(); ++ii )
380 {
381 if( outline.Collide( tri->GetSegment( ii ) ) )
382 {
383 collision = true;
384 return false;
385 }
386 }
387
388 // Also must check for poly being completely inside the triangle
389 if( tri->PointInside( outline.CPoint( 0 ) ) )
390 {
391 collision = true;
392 return false;
393 }
394
395 return true;
396 };
397
398 auto visitor =
399 [&]( ITEM_WITH_SHAPE* aItem ) -> bool
400 {
401 if( aRefShape->Collide( aItem->shape, 0 ) )
402 {
403 collision = true;
404 return false;
405 }
406
407 return true;
408 };
409 auto it = m_tree.find( aLayer );
410
411 if( it == m_tree.end() )
412 return false;
413
414 if( poly && poly->OutlineCount() == 1 && poly->HoleCount( 0 ) == 0 )
415 it->second->Search( min, max, polyVisitor );
416 else
417 it->second->Search( min, max, visitor );
418
419 return collision;
420 }
421
428 std::unordered_set<BOARD_ITEM*> GetObjectsAt( const VECTOR2I& aPt, PCB_LAYER_ID aLayer,
429 int aClearance = 0 )
430 {
431 std::unordered_set<BOARD_ITEM*> retval;
432 int min[2] = { aPt.x - aClearance, aPt.y - aClearance };
433 int max[2] = { aPt.x + aClearance, aPt.y + aClearance };
434
435 auto visitor =
436 [&]( ITEM_WITH_SHAPE* aItem ) -> bool
437 {
438 retval.insert( aItem->parent );
439 return true;
440 };
441
442 m_tree[aLayer]->Search( min, max, visitor );
443
444 return retval;
445 }
446
447 typedef std::pair<PCB_LAYER_ID, PCB_LAYER_ID> LAYER_PAIR;
448
450 {
452 layerPair( aPair ),
453 refItem( aRef ),
454 testItem( aTest )
455 { };
456
460 };
461
462 int QueryCollidingPairs( DRC_RTREE* aRefTree, std::vector<LAYER_PAIR> aLayerPairs,
463 std::function<bool( const LAYER_PAIR&, ITEM_WITH_SHAPE*,
464 ITEM_WITH_SHAPE*, bool* aCollision )> aVisitor,
465 int aMaxClearance,
466 std::function<bool(int, int )> aProgressReporter ) const
467 {
468 std::vector<PAIR_INFO> pairsToVisit;
469
470 for( LAYER_PAIR& layerPair : aLayerPairs )
471 {
472 const PCB_LAYER_ID refLayer = layerPair.first;
473 const PCB_LAYER_ID targetLayer = layerPair.second;
474
475 for( ITEM_WITH_SHAPE* refItem : aRefTree->OnLayer( refLayer ) )
476 {
477 BOX2I box = refItem->shape->BBox();
478 box.Inflate( aMaxClearance );
479
480 int min[2] = { box.GetX(), box.GetY() };
481 int max[2] = { box.GetRight(), box.GetBottom() };
482
483 auto visit =
484 [&]( ITEM_WITH_SHAPE* aItemToTest ) -> bool
485 {
486 // don't collide items against themselves
487 if( aItemToTest->parent == refItem->parent )
488 return true;
489
490 pairsToVisit.emplace_back( layerPair, refItem, aItemToTest );
491 return true;
492 };
493
494 auto it = m_tree.find( targetLayer );
495
496 if( it != m_tree.end() )
497 it->second->Search( min, max, visit );
498 };
499 }
500
501 // keep track of BOARD_ITEMs pairs that have been already found to collide (some items
502 // might be build of COMPOUND/triangulated shapes and a single subshape collision
503 // means we have a hit)
504 std::unordered_map<PTR_PTR_CACHE_KEY, int> collidingCompounds;
505
506 int progress = 0;
507 int count = pairsToVisit.size();
508
509 for( const PAIR_INFO& pair : pairsToVisit )
510 {
511 if( !aProgressReporter( progress++, count ) )
512 break;
513
514 BOARD_ITEM* a = pair.refItem->parent;
515 BOARD_ITEM* b = pair.testItem->parent;
516
517 // store canonical order so we don't collide in both directions (a:b and b:a)
518 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
519 std::swap( a, b );
520
521 // don't report multiple collisions for compound or triangulated shapes
522 if( collidingCompounds.count( { a, b } ) )
523 continue;
524
525 bool collisionDetected = false;
526
527 if( !aVisitor( pair.layerPair, pair.refItem, pair.testItem, &collisionDetected ) )
528 break;
529
530 if( collisionDetected )
531 collidingCompounds[ { a, b } ] = 1;
532 }
533
534 return 0;
535 }
536
542 size_t size() const
543 {
544 return m_count;
545 }
546
547 bool empty() const
548 {
549 return m_count == 0;
550 }
551
552 using iterator = typename drc_rtree::Iterator;
553
563 {
564 DRC_LAYER( drc_rtree* aTree ) : layer_tree( aTree )
565 {
566 m_rect = { { INT_MIN, INT_MIN }, { INT_MAX, INT_MAX } };
567 };
568
569 DRC_LAYER( drc_rtree* aTree, const BOX2I& aRect ) : layer_tree( aTree )
570 {
571 m_rect = { { aRect.GetX(), aRect.GetY() },
572 { aRect.GetRight(), aRect.GetBottom() } };
573 };
574
575 drc_rtree::Rect m_rect;
577
579 {
580 return layer_tree->begin( m_rect );
581 }
582
584 {
585 return layer_tree->end( m_rect );
586 }
587 };
588
590 {
591 auto it = m_tree.find( int( aLayer ) );
592 return it == m_tree.end() ? DRC_LAYER( nullptr ) : DRC_LAYER( it->second );
593 }
594
595 DRC_LAYER Overlapping( PCB_LAYER_ID aLayer, const VECTOR2I& aPoint, int aAccuracy = 0 ) const
596 {
597 BOX2I rect( aPoint, VECTOR2I( 0, 0 ) );
598 rect.Inflate( aAccuracy );
599 auto it = m_tree.find( int( aLayer ) );
600 return it == m_tree.end() ? DRC_LAYER( nullptr ) : DRC_LAYER( it->second, rect );
601 }
602
603 DRC_LAYER Overlapping( PCB_LAYER_ID aLayer, const BOX2I& aRect ) const
604 {
605 auto it = m_tree.find( int( aLayer ) );
606 return it == m_tree.end() ? DRC_LAYER( nullptr ) : DRC_LAYER( it->second, aRect );
607 }
608
609
610private:
611 std::map<int, drc_rtree*> m_tree;
612 size_t m_count;
613};
614
615
616#endif /* DRC_RTREE_H_ */
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
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 > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
BOARD_ITEM_CONTAINER * GetParent() const
Definition board_item.h:215
virtual std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const
virtual bool HasHole() const
Definition board_item.h:161
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:558
constexpr coord_type GetY() const
Definition box2.h:208
constexpr coord_type GetX() const
Definition box2.h:207
constexpr coord_type GetRight() const
Definition box2.h:217
constexpr coord_type GetBottom() const
Definition box2.h:222
DRC_LAYER OnLayer(PCB_LAYER_ID aLayer) const
Definition drc_rtree.h:589
RTree< ITEM_WITH_SHAPE *, int, 2, double > drc_rtree
Definition drc_rtree.h:76
size_t size() const
Return the number of items in the tree.
Definition drc_rtree.h:542
typename drc_rtree::Iterator iterator
Definition drc_rtree.h:552
bool empty() const
Definition drc_rtree.h:547
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:221
void Insert(BOARD_ITEM *aItem, PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer, int aWorstClearance, bool aAtomicTables=false)
Insert an item into the tree on a particular layer with a worst clearance.
Definition drc_rtree.h:110
bool CheckColliding(SHAPE *aRefShape, PCB_LAYER_ID aTargetLayer, int aClearance=0, std::function< bool(BOARD_ITEM *)> aFilter=nullptr) const
Definition drc_rtree.h:182
DRC_LAYER Overlapping(PCB_LAYER_ID aLayer, const BOX2I &aRect) const
Definition drc_rtree.h:603
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:428
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:353
void clear()
Remove all items from the RTree.
Definition drc_rtree.h:169
std::pair< PCB_LAYER_ID, PCB_LAYER_ID > LAYER_PAIR
Definition drc_rtree.h:447
std::map< int, drc_rtree * > m_tree
Definition drc_rtree.h:611
size_t m_count
Definition drc_rtree.h:612
DRC_LAYER Overlapping(PCB_LAYER_ID aLayer, const VECTOR2I &aPoint, int aAccuracy=0) const
Definition drc_rtree.h:595
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:462
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:296
void Insert(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer, 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:101
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:120
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:111
virtual bool IsVisible() const
Definition eda_text.h:187
static const LSET & AllLayersMask()
Definition lset.cpp:641
SHAPE_TYPE Type() const
Return the type of the shape.
Definition shape.h:98
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:126
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.
#define _(s)
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ UNDEFINED_LAYER
Definition layer_ids.h:61
STL namespace.
@ SH_POLY_SET_TRIANGLE
a single triangle belonging to a POLY_SET triangulation
Definition shape.h:56
The DRC_LAYER struct provides a layer-specific auto-range iterator to the RTree.
Definition drc_rtree.h:563
drc_rtree::Rect m_rect
Definition drc_rtree.h:575
drc_rtree * layer_tree
Definition drc_rtree.h:576
DRC_LAYER(drc_rtree *aTree)
Definition drc_rtree.h:564
DRC_LAYER(drc_rtree *aTree, const BOX2I &aRect)
Definition drc_rtree.h:569
ITEM_WITH_SHAPE(BOARD_ITEM *aParent, const SHAPE *aShape, std::shared_ptr< SHAPE > aParentShape=nullptr)
Definition drc_rtree.h:53
std::shared_ptr< SHAPE > parentShape
Definition drc_rtree.h:72
ITEM_WITH_SHAPE(BOARD_ITEM *aParent, const std::shared_ptr< SHAPE > &aShape, std::shared_ptr< SHAPE > aParentShape=nullptr)
Definition drc_rtree.h:61
std::shared_ptr< SHAPE > shapeStorage
Definition drc_rtree.h:71
ITEM_WITH_SHAPE * refItem
Definition drc_rtree.h:458
PAIR_INFO(LAYER_PAIR aPair, ITEM_WITH_SHAPE *aRef, ITEM_WITH_SHAPE *aTest)
Definition drc_rtree.h:451
ITEM_WITH_SHAPE * testItem
Definition drc_rtree.h:459
LAYER_PAIR layerPair
Definition drc_rtree.h:457
int actual
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:90
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:95
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:87
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695