28#include <unordered_set>
39#define ATOMIC_TABLES true
51 std::shared_ptr<SHAPE> aParentShape ) :
59 std::shared_ptr<SHAPE> aParentShape ) :
61 shape( aShape.get() ),
95 int aWorstClearance = 0,
bool aAtomicTables =
false )
97 Insert( aItem, aLayer, aLayer, aConstraintType, aWorstClearance, aAtomicTables );
105 DRC_CONSTRAINT_T aConstraintType,
int aWorstClearance,
bool aAtomicTables =
false )
108 wxCHECK_MSG( !
m_tree.count( aTargetLayer ), , wxT(
"Insert after Build() is silently wrong" ) );
118 std::vector<const SHAPE*> subshapes;
121 wxCHECK2_MSG( shape,
return, wxT(
"Item does not have a valid shape for this layer" ) );
123 if( shape->HasIndexableSubshapes() )
124 shape->GetIndexableSubshapes( subshapes );
126 subshapes.push_back( shape.get() );
128 for(
const SHAPE* subshape : subshapes )
130 if(
dynamic_cast<const SHAPE_NULL*
>( subshape ) )
133 BOX2I bbox = subshape->BBox();
135 bbox.
Inflate( aWorstClearance );
137 const int mmin[2] = { bbox.
GetX(), bbox.
GetY() };
141 m_owned.push_back( itemShape );
142 m_builders[aTargetLayer].Add( mmin, mmax, itemShape );
150 BOX2I bbox = hole->BBox();
152 bbox.
Inflate( aWorstClearance );
154 const int mmin[2] = { bbox.
GetX(), bbox.
GetY() };
158 m_owned.push_back( itemShape );
159 m_builders[aTargetLayer].Add( mmin, mmax, itemShape );
172 m_tree[layer] = builder.Build();
193 std::function<
bool(
BOARD_ITEM*)> aFilter =
nullptr )
const
198 int min[2] = { box.
GetX(), box.
GetY() };
206 if( !aFilter || aFilter( aItem->parent ) )
210 if( aRefShape->
Collide( aItem->shape, aClearance, &
actual ) )
220 if(
auto it =
m_tree.find( aTargetLayer ); it !=
m_tree.end() )
221 it->second.Search( min, max, visit );
236 const std::function<
bool(
BOARD_ITEM*,
int* )>& aClearanceResolver )
const
241 int min[2] = { box.
GetX(), box.
GetY() };
244 bool collision =
false;
248 std::unordered_map<BOARD_ITEM*, std::pair<bool, int>> resolved;
253 auto it = resolved.find( aItem->parent );
255 if( it == resolved.end() )
260 it = resolved.emplace( aItem->parent,
264 if( !it->second.first )
267 if( aRefShape->
Collide( aItem->shape, it->second.second ) )
276 if(
auto it =
m_tree.find( aTargetLayer ); it !=
m_tree.end() )
277 it->second.Search( min, max, visit );
288 std::function<
bool(
BOARD_ITEM* )> aFilter =
nullptr,
289 std::function<
bool(
BOARD_ITEM* )> aVisitor =
nullptr,
290 int aClearance = 0 )
const
295 std::unordered_set<BOARD_ITEM*> collidingCompounds;
299 std::unordered_map<BOARD_ITEM*, bool> filterResults;
304 int min[2] = { box.
GetX(), box.
GetY() };
314 if( aItem->parent == aRefItem )
317 if( collidingCompounds.find( aItem->parent ) != collidingCompounds.end() )
321 auto it = filterResults.find( aItem->parent );
323 if( it == filterResults.end() )
325 filtered = aFilter && !aFilter( aItem->parent );
326 filterResults[ aItem->parent ] = filtered;
330 filtered = it->second;
336 wxCHECK( aItem->shape,
false );
338 if( refShape->Collide( aItem->shape, aClearance ) )
340 collidingCompounds.insert( aItem->parent );
344 return aVisitor( aItem->parent );
350 if(
auto it =
m_tree.find( aTargetLayer ); it !=
m_tree.end() )
351 it->second.Search( min, max, visit );
367 BOARD_ITEM* aRefItem,
const std::shared_ptr<SHAPE>& aRefShape,
369 std::function<
bool(
BOARD_ITEM*,
const std::shared_ptr<SHAPE>& )> aVisitor,
370 int aClearance = 0,
bool aUsePaddingCredit =
false )
const
373 wxCHECK( aRefShape, 0 );
375 std::unordered_set<BOARD_ITEM*> collidingCompounds;
376 std::unordered_map<BOARD_ITEM*, bool> filterResults;
378 int inflation = aClearance;
380 if( aUsePaddingCredit && aClearance >= 0 )
386 bool contained = box.
Contains( aRefShape->BBox() );
388 wxASSERT_MSG( contained, wxT(
"Padding credit needs the item bbox to contain its own shape" ) );
392 if( contained && paddingIt !=
m_minPadding.end() && paddingIt->second >= 0 )
393 inflation = std::max( 0, aClearance - paddingIt->second );
398 int min[2] = { box.
GetX(), box.
GetY() };
405 if( aItem->parent == aRefItem
406 || collidingCompounds.find( aItem->parent ) != collidingCompounds.end() )
411 auto [filterIt, inserted] = filterResults.emplace( aItem->parent,
false );
414 filterIt->second = aFilter && !aFilter( aItem->parent );
416 if( filterIt->second )
419 wxCHECK( aItem->shape,
false );
421 if( aRefShape->Collide( aItem->shape, aClearance ) )
423 collidingCompounds.insert( aItem->parent );
427 return aVisitor( aItem->parent, aItem->parentShape );
433 if(
auto it =
m_tree.find( aTargetLayer ); it !=
m_tree.end() )
434 it->second.Search( min, max, visit );
446 int* aActual,
VECTOR2I* aPos )
const
451 int min[2] = { bbox.
GetX(), bbox.
GetY() };
454 bool collision =
false;
464 if( aRefShape->
Collide( aItem->shape, aClearance, &curActual, &curPos ) )
482 if(
auto it =
m_tree.find( aLayer ); it !=
m_tree.end() )
483 it->second.Search( min, max, visit );
488 *aActual = std::max( 0,
actual );
506 int min[2] = { aBox.
GetX(), aBox.
GetY() };
508 bool collision =
false;
516 const SHAPE* shape = aItem->shape;
528 for(
int ii = 0; ii < (int) tri->GetSegmentCount(); ++ii )
530 if( outline.
Collide( tri->GetSegment( ii ) ) )
538 if( tri->PointInside( outline.
CPoint( 0 ) ) )
550 if( aRefShape->
Collide( aItem->shape, 0 ) )
559 auto it =
m_tree.find( aLayer );
565 it->second.Search( min, max, polyVisitor );
567 it->second.Search( min, max, visitor );
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 };
590 retval.insert( aItem->parent );
594 auto it =
m_tree.find( aLayer );
597 it->second.Search( min, max, visitor );
621 std::function<
bool(
int,
int )> aProgressReporter )
const
623 std::vector<PAIR_INFO> pairsToVisit;
632 BOX2I box = refItem->shape->BBox();
635 int min[2] = { box.
GetX(), box.
GetY() };
642 if( aItemToTest->parent == refItem->parent )
645 pairsToVisit.emplace_back( layerPair, refItem, aItemToTest );
649 auto it =
m_tree.find( targetLayer );
652 it->second.Search( min, max, visit );
659 std::unordered_map<PTR_PTR_CACHE_KEY, int> collidingCompounds;
662 int count = pairsToVisit.size();
664 for(
const PAIR_INFO& pair : pairsToVisit )
666 if( !aProgressReporter( progress++, count ) )
673 if(
static_cast<void*
>( a ) >
static_cast<void*
>( b ) )
677 if( collidingCompounds.count( { a, b } ) )
680 bool collisionDetected =
false;
682 if( !aVisitor( pair.layerPair, pair.refItem, pair.testItem, &collisionDetected ) )
685 if( collisionDetected )
686 collidingCompounds[ { a, b } ] = 1;
727 int min[2] = { aRect.
GetX(), aRect.
GetY() };
736 aTree.
Search( min, max, collector );
741 std::vector<ITEM_WITH_SHAPE*>::iterator
begin() {
return m_items.begin(); }
742 std::vector<ITEM_WITH_SHAPE*>::iterator
end() {
return m_items.end(); }
747 auto it =
m_tree.find( aLayer );
755 auto it =
m_tree.find( aLayer );
761 auto it =
m_tree.find( aLayer );
769 auto [it, inserted] =
m_minPadding.emplace( aLayer, aPadding );
772 it->second = std::min( it->second, aPadding );
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
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
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
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
constexpr coord_type GetY() const
constexpr coord_type GetX() const
constexpr bool Contains(const Vec &aPoint) const
constexpr coord_type GetRight() const
constexpr coord_type GetBottom() const
std::map< int, int > m_minPadding
DRC_LAYER OnLayer(PCB_LAYER_ID aLayer) const
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.
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,...
void recordPadding(PCB_LAYER_ID aLayer, int aPadding)
size_t size() const
Return the number of items in the tree.
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.
typename drc_rtree::Builder drc_rtree_builder
bool CheckColliding(SHAPE *aRefShape, PCB_LAYER_ID aTargetLayer, int aClearance=0, std::function< bool(BOARD_ITEM *)> aFilter=nullptr) const
DRC_LAYER Overlapping(PCB_LAYER_ID aLayer, const BOX2I &aRect) const
KIRTREE::PACKED_RTREE< ITEM_WITH_SHAPE *, int, 2 > drc_rtree
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.
bool QueryColliding(const BOX2I &aBox, SHAPE *aRefShape, PCB_LAYER_ID aLayer) const
Quicker version of above that just reports a raw yes/no.
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...
void clear()
Remove all items from the RTree.
std::pair< PCB_LAYER_ID, PCB_LAYER_ID > LAYER_PAIR
std::map< int, drc_rtree_builder > m_builders
DRC_LAYER Overlapping(PCB_LAYER_ID aLayer, const VECTOR2I &aPoint, int aAccuracy=0) const
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
std::vector< ITEM_WITH_SHAPE * > m_owned
void Build()
Finalize all pending inserts by bulk-building packed R-trees from the staged items.
bool QueryColliding(const BOX2I &aBox, SHAPE *aRefShape, PCB_LAYER_ID aLayer, int aClearance, int *aActual, VECTOR2I *aPos) const
This one is for tessellated items.
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.
std::map< int, drc_rtree > m_tree
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
KICAD_T Type() const
Returns the type of object.
virtual bool IsVisible() const
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.
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.
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,...
virtual const BOX2I BBox(int aClearance=0) const =0
Compute a bounding box of the shape, with a margin of aClearance a collision.
@ DEFAULT
Flashing follows connectivity.
PCB_LAYER_ID
A quick note on layer IDs:
@ SH_POLY_SET_TRIANGLE
a single triangle belonging to a POLY_SET triangulation
The DRC_LAYER struct provides a layer-specific auto-range iterator to the RTree.
DRC_LAYER(const drc_rtree &aTree, const BOX2I &aRect)
DRC_LAYER(const drc_rtree &aTree)
std::vector< ITEM_WITH_SHAPE * >::iterator begin()
std::vector< ITEM_WITH_SHAPE * > m_items
std::vector< ITEM_WITH_SHAPE * >::iterator end()
std::shared_ptr< SHAPE > parentShape
Never null; Insert() only builds these from a shape wxCHECK2_MSG has already validated.
ITEM_WITH_SHAPE(BOARD_ITEM *aParent, const std::shared_ptr< SHAPE > &aShape, std::shared_ptr< SHAPE > aParentShape)
ITEM_WITH_SHAPE(BOARD_ITEM *aParent, const SHAPE *aShape, std::shared_ptr< SHAPE > aParentShape)
std::shared_ptr< SHAPE > shapeStorage
ITEM_WITH_SHAPE * refItem
PAIR_INFO(LAYER_PAIR aPair, ITEM_WITH_SHAPE *aRef, ITEM_WITH_SHAPE *aTest)
ITEM_WITH_SHAPE * testItem
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
@ PCB_PAD_T
class PAD, a pad in a footprint
VECTOR2< int32_t > VECTOR2I