KiCad PCB EDA Suite
Loading...
Searching...
No Matches
connectivity_items.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 (C) 2013-2017 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * @author Maciej Suminski <[email protected]>
8 * @author Tomasz Wlostowski <[email protected]>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
24
25#ifndef PCBNEW_CONNECTIVITY_ITEMS_H
26#define PCBNEW_CONNECTIVITY_ITEMS_H
27
29
30#include <algorithm>
31#include <atomic>
32#include <deque>
33#include <functional>
34#include <memory>
35#include <vector>
36
39
40class CN_ITEM;
41class CN_CLUSTER;
42class PCB_SHAPE;
43
44
50{
51public:
52 CN_ANCHOR( const VECTOR2I& aPos, CN_ITEM* aItem ) :
53 m_pos( aPos ),
54 m_item( aItem ),
55 m_tag( -1 ),
56 m_noline( false )
57 { }
58
59 bool Valid() const;
60
61 bool Dirty() const;
62
63 CN_ITEM* Item() const { return m_item; }
64 void SetItem( CN_ITEM* aItem ) { m_item = aItem; }
65
67
68 const VECTOR2I& Pos() const { return m_pos; }
69
70 void Move( const VECTOR2I& aPos )
71 {
72 m_pos += aPos;
73 }
74
75 unsigned int Dist( const CN_ANCHOR& aSecond )
76 {
77 return ( m_pos - aSecond.Pos() ).EuclideanNorm();
78 }
79
81 int GetTag() const { return m_tag; }
82 void SetTag( int aTag ) { m_tag = aTag; }
83
85 const bool& GetNoLine() const { return m_noline; }
86 void SetNoLine( bool aEnable ) { m_noline = aEnable; }
87
88 const std::shared_ptr<CN_CLUSTER>& GetCluster() const { return m_cluster; }
89 void SetCluster( std::shared_ptr<CN_CLUSTER>& aCluster ) { m_cluster = aCluster; }
90
98 bool IsDangling() const;
99
103 int ConnectedItemsCount() const;
104
105 // Tag used for unconnected items.
106 static const int TAG_UNCONNECTED = -1;
107
108private:
111 int m_tag;
112 bool m_noline;
113
114 std::shared_ptr<CN_CLUSTER> m_cluster;
115};
116
117
118
124{
125public:
126 void Dump();
127
128 CN_ITEM( BOARD_CONNECTED_ITEM* aParent, bool aCanChangeNet, int aAnchorCount = 2 )
129 {
130 m_parent = aParent;
131 m_canChangeNet = aCanChangeNet;
132 m_valid = true;
133 m_dirty = true;
134 m_anchors.reserve( std::max( 6, aAnchorCount ) );
135 m_start_layer = 0;
136 m_end_layer = std::numeric_limits<int>::max();
137 m_connected.reserve( 8 );
138 }
139
140 virtual ~CN_ITEM()
141 {
142 for( const std::shared_ptr<CN_ANCHOR>& anchor : m_anchors )
143 anchor->SetItem( nullptr );
144 };
145
146 std::shared_ptr<CN_ANCHOR> AddAnchor( const VECTOR2I& aPos )
147 {
148 m_anchors.emplace_back( std::make_shared<CN_ANCHOR>( aPos, this ) );
149 return m_anchors.at( m_anchors.size() - 1 );
150 }
151
152 std::vector<std::shared_ptr<CN_ANCHOR>>& Anchors() { return m_anchors; }
153
154 void SetValid( bool aValid ) { m_valid = aValid; }
155 bool Valid() const { return m_valid; }
156
157 void SetDirty( bool aDirty ) { m_dirty.store( aDirty, std::memory_order_release ); }
158 bool Dirty() const { return m_dirty.load( std::memory_order_acquire ); }
159
163 void SetLayers( int aStartLayer, int aEndLayer )
164 {
165 // B_Cu is nominally layer 2 but we reset it to INT_MAX to ensure that it is
166 // always greater than any other layer in the RTree
167 if( aStartLayer == B_Cu )
168 aStartLayer = std::numeric_limits<int>::max();
169
170 if( aEndLayer == B_Cu )
171 aEndLayer = std::numeric_limits<int>::max();
172
173 m_start_layer = aStartLayer;
174 m_end_layer = aEndLayer;
175 }
176
180 void SetLayer( int aLayer ) { SetLayers( aLayer, aLayer ); }
181
185 int StartLayer() const { return m_start_layer; }
186 int EndLayer() const { return m_end_layer; }
187
193 virtual int Layer() const
194 {
195 return StartLayer();
196 }
197
203 {
204 int layer = Layer();
205
206 if( layer == std::numeric_limits<int>::max() )
207 layer = B_Cu;
208
209 return ToLAYER_ID( layer );
210 }
211
212 const BOX2I& BBox()
213 {
214 if( m_dirty.load( std::memory_order_acquire ) && m_valid )
215 {
216 std::lock_guard<std::mutex> lock( m_listLock );
217
218 if( m_dirty.load( std::memory_order_relaxed ) && m_valid )
219 {
220 m_bbox = m_parent->GetBoundingBox();
221 m_dirty.store( false, std::memory_order_release );
222 }
223 }
224
225 return m_bbox;
226 }
227
229
230 const std::vector<CN_ITEM*>& ConnectedItems() const { return m_connected; }
231 void ClearConnections() { m_connected.clear(); }
232
233 bool CanChangeNet() const { return m_canChangeNet; }
234
235 void Connect( CN_ITEM* b )
236 {
237 std::lock_guard<std::mutex> lock( m_listLock );
238
239 auto i = std::lower_bound( m_connected.begin(), m_connected.end(), b );
240
241 if( i != m_connected.end() && *i == b )
242 return;
243
244 m_connected.insert( i, b );
245 }
246
247 void RemoveInvalidRefs();
248
249 virtual int AnchorCount() const;
250 virtual const VECTOR2I GetAnchor( int n ) const;
251
252 int Net() const
253 {
254 return ( !m_parent || !m_valid ) ? -1 : m_parent->GetNetCode();
255 }
256
257protected:
258 std::atomic<bool> m_dirty;
263
264private:
266
267 std::vector<CN_ITEM*> m_connected;
268 std::vector<std::shared_ptr<CN_ANCHOR>> m_anchors;
269
271
272 bool m_valid;
273
274 std::mutex m_listLock;
275};
276
277
278/*
279 * Represents a single outline of a zone fill on a particular layer. \a aSubpolyIndex indicates
280 * which outline in the fill's SHAPE_POLY_SET.
281 */
282class CN_ZONE_LAYER : public CN_ITEM
283{
284public:
285 CN_ZONE_LAYER( ZONE* aParent, PCB_LAYER_ID aLayer, int aSubpolyIndex ) :
286 CN_ITEM( aParent, false ),
287 m_zone( aParent ),
288 m_subpolyIndex( aSubpolyIndex ),
289 m_layer( aLayer )
290 {
291 std::shared_ptr<SHAPE_POLY_SET> fillPoly = aParent->GetFilledPolysList( aLayer );
292
293 if( fillPoly && aSubpolyIndex < fillPoly->OutlineCount() )
294 m_outline = fillPoly->Outline( aSubpolyIndex );
295
296 SetLayers( aLayer, aLayer );
297 }
298
300 {
301 if( m_zone->IsTeardropArea() )
302 return;
303
304 m_triangulatedPolys.clear();
305 m_rTree.RemoveAll();
306
307 std::shared_ptr<SHAPE_POLY_SET> fillPoly = m_zone->GetFilledPolysList( m_layer );
308
309 if( !fillPoly )
310 return;
311
312 for( unsigned int ii = 0; ii < fillPoly->TriangulatedPolyCount(); ++ii )
313 {
314 const auto* triangleSet = fillPoly->TriangulatedPolygon( ii );
315
316 if( triangleSet->GetSourceOutlineIndex() != m_subpolyIndex )
317 continue;
318
319 // Deep copy the triangulated polygon. The copy constructor copies the vertex storage
320 // and updates all TRI parent pointers to reference our owned copy. This ensures the
321 // triangles remain valid even if the zone is refilled on another thread.
322 m_triangulatedPolys.push_back(
323 std::make_unique<SHAPE_POLY_SET::TRIANGULATED_POLYGON>( *triangleSet ) );
324 }
325
326 for( const auto& triPoly : m_triangulatedPolys )
327 {
328 for( const SHAPE_POLY_SET::TRIANGULATED_POLYGON::TRI& tri : triPoly->Triangles() )
329 {
330 BOX2I bbox = tri.BBox();
331 const int mmin[2] = { bbox.GetX(), bbox.GetY() };
332 const int mmax[2] = { bbox.GetRight(), bbox.GetBottom() };
333
334 m_rTree.Insert( mmin, mmax, &tri );
335 }
336 }
337 }
338
339 int SubpolyIndex() const { return m_subpolyIndex; }
340
341 PCB_LAYER_ID GetLayer() const { return m_layer; }
342
343 bool ContainsPoint( const VECTOR2I& p ) const
344 {
345 if( m_outline.PointCount() == 0 )
346 return false;
347
348 if( m_zone->IsTeardropArea() )
349 return m_outline.Collide( p );
350
351 int min[2] = { p.x, p.y };
352 int max[2] = { p.x, p.y };
353 bool collision = false;
354
355 auto visitor =
356 [&]( const SHAPE* aShape ) -> bool
357 {
358 if( aShape->Collide( p ) )
359 {
360 collision = true;
361 return false;
362 }
363
364 return true;
365 };
366
367 m_rTree.Search( min, max, visitor );
368
369 return collision;
370 }
371
373
374 virtual int AnchorCount() const override;
375 virtual const VECTOR2I GetAnchor( int n ) const override;
376
377 bool HasValidOutline() const
378 {
379 return m_outline.PointCount() > 0;
380 }
381
383 {
384 return m_outline;
385 }
386
388 {
389 return m_outline.PointCount();
390 }
391
392 const VECTOR2I& OutlinePoint( int aIndex ) const
393 {
394 return m_outline.CPoint( aIndex );
395 }
396
397 bool Collide( SHAPE* aRefShape ) const
398 {
399 if( m_outline.PointCount() == 0 )
400 return false;
401
402 if( m_zone->IsTeardropArea() )
403 return aRefShape->Collide( &m_outline, 0 );
404
405 BOX2I bbox = aRefShape->BBox();
406 int min[2] = { bbox.GetX(), bbox.GetY() };
407 int max[2] = { bbox.GetRight(), bbox.GetBottom() };
408 bool collision = false;
409
410 auto visitor =
411 [&]( const SHAPE* aShape ) -> bool
412 {
413 if( aRefShape->Collide( aShape ) )
414 {
415 collision = true;
416 return false;
417 }
418
419 return true;
420 };
421
422 m_rTree.Search( min, max, visitor );
423
424 return collision;
425 }
426
427 bool HasSingleConnection();
428
429private:
435 std::vector<std::unique_ptr<SHAPE_POLY_SET::TRIANGULATED_POLYGON>> m_triangulatedPolys;
437};
438
439
440
441
443{
444public:
446 {
447 m_dirty = false;
448 m_hasInvalid = false;
449 }
450
451 void Clear()
452 {
453 for( CN_ITEM* item : m_items )
454 delete item;
455
456 m_items.clear();
457 m_index.RemoveAll();
458 }
459
460 std::vector<CN_ITEM*>::iterator begin() { return m_items.begin(); };
461 std::vector<CN_ITEM*>::iterator end() { return m_items.end(); };
462
463 std::vector<CN_ITEM*>::const_iterator begin() const { return m_items.begin(); }
464 std::vector<CN_ITEM*>::const_iterator end() const { return m_items.end(); }
465
466 CN_ITEM* operator[] ( int aIndex ) { return m_items[aIndex]; }
467
468 template <class T>
469 void FindNearby( CN_ITEM* aItem, T aFunc )
470 {
471 m_index.Query( aItem->BBox(), aItem->StartLayer(), aItem->EndLayer(), aFunc );
472 }
473
474 void SetHasInvalid( bool aInvalid = true ) { m_hasInvalid = aInvalid; }
475
476 void SetDirty( bool aDirty = true ) { m_dirty = aDirty; }
477 bool IsDirty() const { return m_dirty; }
478
479 void RemoveInvalidItems( std::vector<CN_ITEM*>& aGarbage );
480
482 {
483 for( CN_ITEM* item : m_items )
484 item->SetDirty( false );
485
486 SetDirty( false );
487 }
488
489 int Size() const { return m_items.size(); }
490
491 CN_ITEM* Add( PAD* pad );
492 CN_ITEM* Add( PCB_TRACK* track );
493 CN_ITEM* Add( PCB_ARC* track );
494 CN_ITEM* Add( PCB_VIA* via );
495 CN_ITEM* Add( CN_ZONE_LAYER* zitem );
496 CN_ITEM* Add( PCB_SHAPE* shape );
497
498 const std::vector<CN_ITEM*> Add( ZONE* zone, PCB_LAYER_ID aLayer );
499
500protected:
501 void addItemtoTree( CN_ITEM* item )
502 {
503 m_index.Insert( item );
504 }
505
506protected:
507 std::vector<CN_ITEM*> m_items;
508
509private:
513};
514
515
517{
518public:
519 CN_CLUSTER();
520 ~CN_CLUSTER();
521
522 bool HasValidNet() const { return m_originNet > 0; }
523 int OriginNet() const { return m_originNet; }
524
525 wxString OriginNetName() const;
526
527 bool Contains( const CN_ITEM* aItem );
528 bool Contains( const BOARD_CONNECTED_ITEM* aItem );
529 void Dump();
530
531 int Size() const { return m_items.size(); }
532
533 bool IsOrphaned() const
534 {
535 return m_originPad == nullptr;
536 }
537
538 bool IsConflicting() const { return m_conflicting; }
539
540 void Add( CN_ITEM* item );
541
542 std::vector<CN_ITEM*>::iterator begin() { return m_items.begin(); };
543 std::vector<CN_ITEM*>::iterator end() { return m_items.end(); };
544
545private:
549 std::vector<CN_ITEM*> m_items;
550 std::unordered_map<int, int> m_netRanks;
551};
552
553
554
555#endif /* PCBNEW_CONNECTIVITY_ITEMS_H */
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
constexpr coord_type GetY() const
Definition box2.h:204
constexpr coord_type GetX() const
Definition box2.h:203
constexpr coord_type GetRight() const
Definition box2.h:213
constexpr coord_type GetBottom() const
Definition box2.h:218
void SetTag(int aTag)
CN_ITEM * m_item
Pad or track/arc/via owning the anchor.
static const int TAG_UNCONNECTED
VECTOR2I m_pos
Position of the anchor.
void Move(const VECTOR2I &aPos)
bool Valid() const
void SetNoLine(bool aEnable)
int ConnectedItemsCount() const
std::shared_ptr< CN_CLUSTER > m_cluster
Cluster to which the anchor belongs.
CN_ANCHOR(const VECTOR2I &aPos, CN_ITEM *aItem)
const bool & GetNoLine() const
int GetTag() const
const std::shared_ptr< CN_CLUSTER > & GetCluster() const
unsigned int Dist(const CN_ANCHOR &aSecond)
void SetCluster(std::shared_ptr< CN_CLUSTER > &aCluster)
const VECTOR2I & Pos() const
bool Dirty() const
CN_ITEM * Item() const
int m_tag
Tag for quick connection resolution.
bool m_noline
Whether it the node can be a target for ratsnest lines.
BOARD_CONNECTED_ITEM * Parent() const
bool IsDangling() const
The anchor point is dangling if the parent is a track and this anchor point is not connected to anoth...
void SetItem(CN_ITEM *aItem)
int Size() const
std::vector< CN_ITEM * >::iterator end()
std::vector< CN_ITEM * > m_items
bool IsConflicting() const
bool IsOrphaned() const
bool Contains(const CN_ITEM *aItem)
void Add(CN_ITEM *item)
CN_ITEM * m_originPad
std::vector< CN_ITEM * >::iterator begin()
wxString OriginNetName() const
std::unordered_map< int, int > m_netRanks
bool HasValidNet() const
int OriginNet() const
CN_ITEM represents a BOARD_CONNETED_ITEM in the connectivity system (ie: a pad, track/arc/via,...
virtual int Layer() const
Return the item's layer, for single-layered items only.
void Connect(CN_ITEM *b)
virtual ~CN_ITEM()
const BOX2I & BBox()
virtual int AnchorCount() const
void RemoveInvalidRefs()
std::vector< CN_ITEM * > m_connected
list of physically touching items
const std::vector< CN_ITEM * > & ConnectedItems() const
int Net() const
int m_start_layer
start layer of the item N.B. B_Cu is set to INT_MAX
void SetValid(bool aValid)
std::atomic< bool > m_dirty
used to identify recently added item not yet scanned into the connectivity search
BOARD_CONNECTED_ITEM * m_parent
int m_end_layer
end layer of the item N.B. B_Cu is set to INT_MAX
bool Valid() const
int StartLayer() const
Return the contiguous set of layers spanned by the item.
std::shared_ptr< CN_ANCHOR > AddAnchor(const VECTOR2I &aPos)
void SetLayers(int aStartLayer, int aEndLayer)
Set the layers spanned by the item to aStartLayer and aEndLayer.
void ClearConnections()
BOX2I m_bbox
bounding box for the item
virtual const VECTOR2I GetAnchor(int n) const
PCB_LAYER_ID GetBoardLayer() const
When using CN_ITEM layers to compare against board items, use this function which correctly remaps th...
bool m_canChangeNet
can the net propagator modify the netcode?
void SetDirty(bool aDirty)
bool CanChangeNet() const
CN_ITEM(BOARD_CONNECTED_ITEM *aParent, bool aCanChangeNet, int aAnchorCount=2)
int EndLayer() const
void SetLayer(int aLayer)
Set the layers spanned by the item to a single layer aLayer.
std::vector< std::shared_ptr< CN_ANCHOR > > m_anchors
bool m_valid
used to identify garbage items (we use lazy removal)
bool Dirty() const
std::vector< std::shared_ptr< CN_ANCHOR > > & Anchors()
BOARD_CONNECTED_ITEM * Parent() const
std::mutex m_listLock
mutex protecting this item's connected_items set to
CN_RTREE< CN_ITEM * > m_index
CN_ITEM * operator[](int aIndex)
CN_ITEM * Add(PAD *pad)
std::vector< CN_ITEM * >::iterator begin()
std::vector< CN_ITEM * >::const_iterator begin() const
void SetDirty(bool aDirty=true)
int Size() const
std::vector< CN_ITEM * >::const_iterator end() const
bool IsDirty() const
std::vector< CN_ITEM * >::iterator end()
std::vector< CN_ITEM * > m_items
void FindNearby(CN_ITEM *aItem, T aFunc)
void ClearDirtyFlags()
void addItemtoTree(CN_ITEM *item)
void SetHasInvalid(bool aInvalid=true)
void RemoveInvalidItems(std::vector< CN_ITEM * > &aGarbage)
CN_RTREE - Implements an R-tree for fast spatial indexing of connectivity items.
virtual int AnchorCount() const override
const SHAPE_LINE_CHAIN & GetOutline() const
CN_ZONE_LAYER(ZONE *aParent, PCB_LAYER_ID aLayer, int aSubpolyIndex)
std::vector< std::unique_ptr< SHAPE_POLY_SET::TRIANGULATED_POLYGON > > m_triangulatedPolys
virtual const VECTOR2I GetAnchor(int n) const override
const VECTOR2I & OutlinePoint(int aIndex) const
PCB_LAYER_ID GetLayer() const
bool Collide(SHAPE *aRefShape) const
int SubpolyIndex() const
KIRTREE::DYNAMIC_RTREE< const SHAPE *, int, 2 > m_rTree
int OutlinePointCount() const
PCB_LAYER_ID m_layer
SHAPE_LINE_CHAIN m_outline
Cached copy of the zone outline.
PCB_LAYER_ID GetLayer()
bool ContainsPoint(const VECTOR2I &p) const
bool HasValidOutline() const
Dynamic R*-tree with SoA node layout and stored insertion bounding boxes.
Definition pad.h:61
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
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.
Handle a list of polygons defining a copper zone.
Definition zone.h:70
std::shared_ptr< SHAPE_POLY_SET > GetFilledPolysList(PCB_LAYER_ID aLayer) const
Definition zone.h:697
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ B_Cu
Definition layer_ids.h:61
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:750
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683