32#include <unordered_set>
36#include <geometry/rtree.h>
55 std::shared_ptr<SHAPE> aParentShape =
nullptr ) :
63 std::shared_ptr<SHAPE> aParentShape =
nullptr ) :
65 shape( aShape.get() ),
78 using drc_rtree = RTree<ITEM_WITH_SHAPE*, int, 2, double>;
106 Insert( aItem, aLayer, aLayer, aWorstClearance );
114 int aWorstClearance )
124 std::vector<const SHAPE*> subshapes;
127 wxCHECK2_MSG( shape,
return, wxT(
"Item does not have a valid shape for this layer" ) );
129 if( shape->HasIndexableSubshapes() )
130 shape->GetIndexableSubshapes( subshapes );
132 subshapes.push_back( shape.get() );
134 for(
const SHAPE* subshape : subshapes )
136 if(
dynamic_cast<const SHAPE_NULL*
>( subshape ) )
139 BOX2I bbox = subshape->BBox();
141 bbox.
Inflate( aWorstClearance );
143 const int mmin[2] = { bbox.
GetX(), bbox.
GetY() };
147 m_tree[aTargetLayer]->Insert( mmin, mmax, itemShape );
154 BOX2I bbox = hole->BBox();
156 bbox.
Inflate( aWorstClearance );
158 const int mmin[2] = { bbox.
GetX(), bbox.
GetY() };
162 m_tree[aTargetLayer]->Insert( mmin, mmax, itemShape );
179 std::function<
bool(
BOARD_ITEM*)> aFilter =
nullptr )
const
184 int min[2] = { box.
GetX(), box.
GetY() };
192 if( !aFilter || aFilter( aItem->parent ) )
196 if( aRefShape->
Collide( aItem->shape, aClearance, &actual ) )
206 this->
m_tree[aTargetLayer]->Search( min, max, visit );
216 std::function<
bool(
BOARD_ITEM* )> aFilter =
nullptr,
217 std::function<
bool(
BOARD_ITEM* )> aVisitor =
nullptr,
218 int aClearance = 0 )
const
223 std::unordered_set<BOARD_ITEM*> collidingCompounds;
227 std::unordered_map<BOARD_ITEM*, bool> filterResults;
232 int min[2] = { box.
GetX(), box.
GetY() };
242 if( aItem->parent == aRefItem )
245 if( collidingCompounds.find( aItem->parent ) != collidingCompounds.end() )
249 auto it = filterResults.find( aItem->parent );
251 if( it == filterResults.end() )
253 filtered = aFilter && !aFilter( aItem->parent );
254 filterResults[ aItem->parent ] = filtered;
258 filtered = it->second;
264 wxCHECK( aItem->shape,
false );
266 if( refShape->Collide( aItem->shape, aClearance ) )
268 collidingCompounds.insert( aItem->parent );
272 return aVisitor( aItem->parent );
278 this->
m_tree[aTargetLayer]->Search( min, max, visit );
289 int* aActual,
VECTOR2I* aPos )
const
294 int min[2] = { bbox.
GetX(), bbox.
GetY() };
297 bool collision =
false;
298 int actual = INT_MAX;
307 if( aRefShape->
Collide( aItem->shape, aClearance, &curActual, &curPos ) )
311 if( curActual < actual )
325 this->
m_tree[aLayer]->Search( min, max, visit );
330 *aActual = std::max( 0, actual );
348 int min[2] = { aBox.
GetX(), aBox.
GetY() };
350 bool collision =
false;
358 const SHAPE* shape = aItem->shape;
364 for(
int ii = 0; ii < (int) tri->GetSegmentCount(); ++ii )
366 if( outline.
Collide( tri->GetSegment( ii ) ) )
374 if( tri->PointInside( outline.
CPoint( 0 ) ) )
386 if( aRefShape->
Collide( aItem->shape, 0 ) )
396 this->
m_tree[aLayer]->Search( min, max, polyVisitor );
398 this->
m_tree[aLayer]->Search( min, max, visitor );
412 std::unordered_set<BOARD_ITEM*> retval;
413 int min[2] = { aPt.
x - aClearance, aPt.
y - aClearance };
414 int max[2] = { aPt.
x + aClearance, aPt.
y + aClearance };
419 retval.insert( aItem->parent );
423 m_tree[aLayer]->Search( min, max, visitor );
447 std::function<
bool(
int,
int )> aProgressReporter )
const
449 std::vector<PAIR_INFO> pairsToVisit;
458 BOX2I box = refItem->shape->BBox();
461 int min[2] = { box.
GetX(), box.
GetY() };
468 if( aItemToTest->parent == refItem->parent )
471 pairsToVisit.emplace_back( layerPair, refItem, aItemToTest );
475 this->
m_tree[targetLayer]->Search( min, max, visit );
482 std::unordered_map<PTR_PTR_CACHE_KEY, int> collidingCompounds;
485 int count = pairsToVisit.size();
487 for(
const PAIR_INFO& pair : pairsToVisit )
489 if( !aProgressReporter( progress++, count ) )
496 if(
static_cast<void*
>( a ) >
static_cast<void*
>( b ) )
500 if( collidingCompounds.count( { a, b } ) )
503 bool collisionDetected =
false;
505 if( !aVisitor( pair.layerPair, pair.refItem, pair.testItem, &collisionDetected ) )
508 if( collisionDetected )
509 collidingCompounds[ { a, b } ] = 1;
544 m_rect = { { INT_MIN, INT_MIN }, { INT_MAX, INT_MAX } };
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
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.
virtual std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const
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 coord_type GetRight() const
constexpr coord_type GetBottom() const
Implement an R-tree for fast spatial and layer indexing of connectable items.
DRC_LAYER OnLayer(PCB_LAYER_ID aLayer) const
void Insert(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer, int aWorstClearance=0)
Insert an item into the tree on a particular layer with an optional worst clearance.
void Insert(BOARD_ITEM *aItem, PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer, int aWorstClearance)
Insert an item into the tree on a particular layer with a worst clearance.
RTree< ITEM_WITH_SHAPE *, int, 2, double > drc_rtree
size_t size() const
Return the number of items in the tree.
typename drc_rtree::Iterator iterator
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.
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
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.
drc_rtree * m_tree[PCB_LAYER_ID_COUNT]
bool QueryColliding(const BOX2I &aBox, SHAPE *aRefShape, PCB_LAYER_ID aLayer) const
Quicker version of above that just reports a raw yes/no.
void clear()
Remove all items from the RTree.
std::pair< PCB_LAYER_ID, PCB_LAYER_ID > LAYER_PAIR
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
bool QueryColliding(const BOX2I &aBox, SHAPE *aRefShape, PCB_LAYER_ID aLayer, int aClearance, int *aActual, VECTOR2I *aPos) const
This one is for tessellated items.
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 LSET AllLayersMask()
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.
PCB_LAYER_ID
A quick note on layer IDs:
The DRC_LAYER struct provides a layer-specific auto-range iterator to the RTree.
DRC_LAYER(drc_rtree *aTree)
DRC_LAYER(drc_rtree *aTree, const BOX2I &aRect)
ITEM_WITH_SHAPE(BOARD_ITEM *aParent, const SHAPE *aShape, std::shared_ptr< SHAPE > aParentShape=nullptr)
std::shared_ptr< SHAPE > parentShape
ITEM_WITH_SHAPE(BOARD_ITEM *aParent, const std::shared_ptr< SHAPE > &aShape, std::shared_ptr< SHAPE > aParentShape=nullptr)
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_TEXT_T
class PCB_TEXT, text on a layer
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
@ PCB_PAD_T
class PAD, a pad in a footprint
VECTOR2< int32_t > VECTOR2I