KiCad PCB EDA Suite
Loading...
Searching...
No Matches
connectivity_items.cpp
Go to the documentation of this file.
1
2/*
3 * This program source code file is part of KICAD, a free EDA CAD application.
4 *
5 * Copyright (C) 2016-2018 CERN
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
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, you may find one here:
22 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
23 * or you may search the http://www.gnu.org website for the version 2 license,
24 * or you may write to the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26 */
27
28#include <core/kicad_algo.h>
29#include <macros.h>
31#include <trigo.h>
32
33#include <footprint.h>
34#include <pad.h>
35#include <pcb_shape.h>
36#include <pcb_track.h>
37
38#include <wx/log.h>
39
41{
42 if( !m_valid )
43 return 0;
44
45 switch( m_parent->Type() )
46 {
47 case PCB_TRACE_T:
48 case PCB_ARC_T:
49 return 2; // start and end
50
51 case PCB_SHAPE_T:
52 return m_anchors.size();
53
54 default:
55 return 1;
56 }
57}
58
59
60const VECTOR2I CN_ITEM::GetAnchor( int n ) const
61{
62 if( !m_valid )
63 return VECTOR2I();
64
65 switch( m_parent->Type() )
66 {
67 case PCB_PAD_T:
68 return static_cast<PAD*>( m_parent )->GetPosition();
69
70 case PCB_TRACE_T:
71 case PCB_ARC_T:
72 if( n == 0 )
73 return static_cast<const PCB_TRACK*>( m_parent )->GetStart();
74 else
75 return static_cast<const PCB_TRACK*>( m_parent )->GetEnd();
76
77 case PCB_VIA_T:
78 return static_cast<const PCB_VIA*>( m_parent )->GetStart();
79
80 case PCB_SHAPE_T:
81 return ( n < static_cast<int>( m_anchors.size() ) ) ? m_anchors[n]->Pos() : VECTOR2I();
82
83 default:
84 UNIMPLEMENTED_FOR( m_parent->GetClass() );
85 return VECTOR2I();
86 }
87}
88
89
91{
92 wxLogTrace( wxT( "CN" ), wxT( " valid: %d, connected: \n" ), !!Valid() );
93
94 for( CN_ITEM* i : m_connected )
95 {
96 PCB_TRACK* t = static_cast<PCB_TRACK*>( i->Parent() );
97 wxLogTrace( wxT( "CN" ), wxT( " - %p %d\n" ), t, t->Type() );
98 }
99}
100
101
103{
104 if( !Valid() || !HasValidOutline() )
105 return 0;
106
107 return GetOutline().PointCount() ? 1 : 0;
108}
109
110
112{
113 if( !Valid() || !HasValidOutline() )
114 return VECTOR2I();
115
116 return GetOutline().CPoint( 0 );
117}
118
119
121{
122 int count = 0;
123
124 for( CN_ITEM* item : ConnectedItems() )
125 {
126 if( item->Valid() )
127 count++;
128
129 if( count > 1 )
130 break;
131 }
132
133 return count == 1;
134}
135
136
138{
139 for( auto it = m_connected.begin(); it != m_connected.end(); /* increment in loop */ )
140 {
141 if( !(*it)->Valid() )
142 it = m_connected.erase( it );
143 else
144 ++it;
145 }
146}
147
148
150{
151 if( !pad->IsOnCopperLayer() )
152 return nullptr;
153
154 auto item = new CN_ITEM( pad, false, 1 );
155
156 std::set<VECTOR2I> uniqueAnchors;
157 pad->Padstack().ForEachUniqueLayer(
158 [&]( PCB_LAYER_ID aLayer )
159 {
160 uniqueAnchors.insert( pad->ShapePos( aLayer ) );
161 } );
162
163 for( const VECTOR2I& anchor : uniqueAnchors )
164 item->AddAnchor( anchor );
165
166 item->SetLayers( F_Cu, B_Cu );
167
168 switch( pad->GetAttribute() )
169 {
170 case PAD_ATTRIB::SMD:
171 case PAD_ATTRIB::NPTH:
172 case PAD_ATTRIB::CONN:
173 {
174 LSEQ lmsk = pad->GetLayerSet().CuStack();
175
176 if( !lmsk.empty() )
177 item->SetLayer( lmsk.front() );
178
179 break;
180 }
181
182 default:
183 break;
184 }
185
186 addItemtoTree( item );
187 m_items.push_back( item );
188
189 // Re-mark dirty after tree insertion since BBox() clears the dirty flag
190 item->SetDirty( true );
191 SetDirty();
192 return item;
193}
194
195
197{
198 CN_ITEM* item = new CN_ITEM( track, true );
199 m_items.push_back( item );
200 item->AddAnchor( track->GetStart() );
201 item->AddAnchor( track->GetEnd() );
202 item->SetLayer( track->GetLayer() );
203 addItemtoTree( item );
204
205 // Re-mark dirty after tree insertion since BBox() clears the dirty flag
206 item->SetDirty( true );
207 SetDirty();
208 return item;
209}
210
211
213{
214 CN_ITEM* item = new CN_ITEM( aArc, true );
215 m_items.push_back( item );
216 item->AddAnchor( aArc->GetStart() );
217 item->AddAnchor( aArc->GetEnd() );
218 item->SetLayer( aArc->GetLayer() );
219 addItemtoTree( item );
220
221 // Re-mark dirty after tree insertion since BBox() clears the dirty flag
222 item->SetDirty( true );
223 SetDirty();
224 return item;
225}
226
227
229{
230 CN_ITEM* item = new CN_ITEM( via, !via->GetIsFree(), 1 );
231
232 m_items.push_back( item );
233 item->AddAnchor( via->GetStart() );
234
235 item->SetLayers( via->TopLayer(), via->BottomLayer() );
236 addItemtoTree( item );
237
238 // Re-mark dirty after tree insertion since BBox() clears the dirty flag
239 item->SetDirty( true );
240 SetDirty();
241 return item;
242}
243
244
245const std::vector<CN_ITEM*> CN_LIST::Add( ZONE* zone, PCB_LAYER_ID aLayer )
246{
247 const std::shared_ptr<SHAPE_POLY_SET>& polys = zone->GetFilledPolysList( aLayer );
248
249 std::vector<CN_ITEM*> rv;
250
251 for( int j = 0; j < polys->OutlineCount(); j++ )
252 {
253 CN_ZONE_LAYER* zitem = new CN_ZONE_LAYER( zone, aLayer, j );
254
255 zitem->BuildRTree();
256
257 for( const VECTOR2I& pt : zone->GetFilledPolysList( aLayer )->COutline( j ).CPoints() )
258 zitem->AddAnchor( pt );
259
260 rv.push_back( Add( zitem ) );
261 }
262
263 return rv;
264}
265
266
268{
269 m_items.push_back( zitem );
270 addItemtoTree( zitem );
271
272 // Re-mark dirty after tree insertion since BBox() clears the dirty flag
273 zitem->SetDirty( true );
274 SetDirty();
275 return zitem;
276}
277
278
280{
281 CN_ITEM* item = new CN_ITEM( shape, true );
282 m_items.push_back( item );
283
284 for( const VECTOR2I& point : shape->GetConnectionPoints() )
285 item->AddAnchor( point );
286
287 item->SetLayer( shape->GetLayer() );
288 addItemtoTree( item );
289
290 // Re-mark dirty after tree insertion since BBox() clears the dirty flag
291 item->SetDirty( true );
292 SetDirty();
293 return item;
294}
295
296
297void CN_LIST::RemoveInvalidItems( std::vector<CN_ITEM*>& aGarbage )
298{
299 if( !m_hasInvalid )
300 return;
301
302 auto lastItem = std::remove_if( m_items.begin(), m_items.end(),
303 [&aGarbage]( CN_ITEM* item )
304 {
305 if( !item->Valid() )
306 {
307 aGarbage.push_back ( item );
308 return true;
309 }
310
311 return false;
312 } );
313
314 m_items.resize( lastItem - m_items.begin() );
315
316 for( CN_ITEM* item : aGarbage )
317 m_index.Remove( item );
318
319 m_hasInvalid = false;
320}
321
322
324{
325 assert( m_item->Valid() );
326 return m_item->Parent();
327}
328
329
331{
332 if( !m_item )
333 return false;
334
335 return m_item->Valid();
336}
337
338
340{
341 return !Valid() || m_item->Dirty();
342}
343
344
346{
347 int accuracy = 0;
348
349 if( !m_cluster )
350 return true;
351
352 // the minimal number of items connected to item_ref
353 // at this anchor point to decide the anchor is *not* dangling
354 size_t minimal_count = 1;
355 size_t connected_count = m_item->ConnectedItems().size();
356
357 // a via can be removed if connected to only one other item.
358 if( Parent()->Type() == PCB_VIA_T )
359 return connected_count < 2;
360
361 if( m_item->AnchorCount() == 1 )
362 return connected_count < minimal_count;
363
364 if( Parent()->Type() == PCB_TRACE_T || Parent()->Type() == PCB_ARC_T )
365 accuracy = KiROUND( static_cast<const PCB_TRACK*>( Parent() )->GetWidth() / 2.0 );
366 else if( Parent()->Type() == PCB_SHAPE_T )
367 accuracy = KiROUND( static_cast<const PCB_SHAPE*>( Parent() )->GetWidth() / 2.0 );
368
369 // Items with multiple anchors have usually items connected to each anchor.
370 // We want only the item count of this anchor point
371 connected_count = 0;
372
373 for( CN_ITEM* item : m_item->ConnectedItems() )
374 {
375 if( item->Parent()->Type() == PCB_ZONE_T )
376 {
377 ZONE* zone = static_cast<ZONE*>( item->Parent() );
378
379 if( zone->HitTestFilledArea( item->GetBoardLayer(), Pos(), accuracy ) )
380 connected_count++;
381 }
382 else if( item->Parent()->HitTest( Pos(), accuracy ) )
383 {
384 connected_count++;
385 }
386 }
387
388 return connected_count < minimal_count;
389}
390
391
393{
394 if( !m_cluster )
395 return 0;
396
397 int connected_count = 0;
398
399 for( CN_ITEM* item : m_item->ConnectedItems() )
400 {
401 if( item->Parent()->Type() == PCB_ZONE_T )
402 {
403 ZONE* zone = static_cast<ZONE*>( item->Parent() );
404
405 if( zone->HitTestFilledArea( item->GetBoardLayer(), Pos() ) )
406 connected_count++;
407 }
408 else if( item->Parent()->HitTest( Pos() ) )
409 {
410 connected_count++;
411 }
412 }
413
414 return connected_count;
415}
416
417
419{
420 m_items.reserve( 64 );
421 m_originPad = nullptr;
422 m_originNet = -1;
423 m_conflicting = false;
424}
425
426
430
431
433{
434 if( !m_originPad || !m_originPad->Valid() )
435 return "<none>";
436 else
437 return m_originPad->Parent()->GetNetname();
438}
439
440
441bool CN_CLUSTER::Contains( const CN_ITEM* aItem )
442{
443 return alg::contains( m_items, aItem );
444}
445
446
448{
449 return std::find_if( m_items.begin(), m_items.end(),
450 [&aItem]( const CN_ITEM* item )
451 {
452 return item->Valid() && item->Parent() == aItem;
453 } ) != m_items.end();
454}
455
456
458{
459 for( CN_ITEM* item : m_items )
460 {
461 wxLogTrace( wxT( "CN" ), wxT( " - item : %p bitem : %p type : %d inet %s\n" ),
462 item,
463 item->Parent(),
464 item->Parent()->Type(),
465 (const char*) item->Parent()->GetNetname().c_str() );
466 wxLogTrace( wxT( "CN" ), wxT( "- item : %p bitem : %p type : %d inet %s\n" ),
467 item,
468 item->Parent(),
469 item->Parent()->Type(),
470 (const char*) item->Parent()->GetNetname().c_str() );
471 item->Dump();
472 }
473}
474
475
477{
478 m_items.push_back( item );
479
480 int netCode = item->Net();
481
482 if( netCode <= 0 )
483 return;
484
485 if( m_originNet <= 0 )
486 {
487 m_originNet = netCode;
489 }
490
491 if( item->Parent()->Type() == PCB_PAD_T && !static_cast<PAD*>( item->Parent() )->IsFreePad() )
492 {
493 int rank;
494 auto it = m_netRanks.find( netCode );
495
496 if( it == m_netRanks.end() )
497 {
498 m_netRanks[netCode] = 1;
499 rank = 1;
500 }
501 else
502 {
503 it->second++;
504 rank = it->second;
505 }
506
507 if( !m_originPad || rank > m_netRanks[m_originNet] )
508 {
509 m_originPad = item;
510 m_originNet = netCode;
511 }
512
513 if( m_originPad && item->Net() != m_originNet )
514 m_conflicting = true;
515 }
516}
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
CN_ITEM * m_item
Pad or track/arc/via owning the anchor.
bool Valid() const
int ConnectedItemsCount() const
std::shared_ptr< CN_CLUSTER > m_cluster
Cluster to which the anchor belongs.
const VECTOR2I & Pos() const
bool Dirty() const
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...
std::vector< CN_ITEM * > m_items
bool Contains(const CN_ITEM *aItem)
void Add(CN_ITEM *item)
CN_ITEM * m_originPad
wxString OriginNetName() const
std::unordered_map< int, int > m_netRanks
CN_ITEM represents a BOARD_CONNETED_ITEM in the connectivity system (ie: a pad, track/arc/via,...
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
BOARD_CONNECTED_ITEM * m_parent
bool Valid() const
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.
virtual const VECTOR2I GetAnchor(int n) const
void SetDirty(bool aDirty)
CN_ITEM(BOARD_CONNECTED_ITEM *aParent, bool aCanChangeNet, int aAnchorCount=2)
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)
BOARD_CONNECTED_ITEM * Parent() const
CN_ITEM * Add(PAD *pad)
void SetDirty(bool aDirty=true)
std::vector< CN_ITEM * > m_items
void addItemtoTree(CN_ITEM *item)
void RemoveInvalidItems(std::vector< CN_ITEM * > &aGarbage)
virtual int AnchorCount() const override
const SHAPE_LINE_CHAIN & GetOutline() const
virtual const VECTOR2I GetAnchor(int n) const override
bool HasValidOutline() const
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:111
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition lseq.h:47
Definition pad.h:55
bool IsFreePad() const
Definition pad.cpp:363
std::vector< VECTOR2I > GetConnectionPoints() const
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition pcb_shape.h:71
const VECTOR2I & GetStart() const
Definition pcb_track.h:97
const VECTOR2I & GetEnd() const
Definition pcb_track.h:94
int PointCount() const
Return the number of points (vertices) in this line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
const std::vector< VECTOR2I > & CPoints() const
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Handle a list of polygons defining a copper zone.
Definition zone.h:73
std::shared_ptr< SHAPE_POLY_SET > GetFilledPolysList(PCB_LAYER_ID aLayer) const
Definition zone.h:606
bool HitTestFilledArea(PCB_LAYER_ID aLayer, const VECTOR2I &aRefPos, int aAccuracy=0) const
Test if the given VECTOR2I is within the bounds of a filled area of this zone.
Definition zone.cpp:852
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ B_Cu
Definition layer_ids.h:65
@ F_Cu
Definition layer_ids.h:64
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:96
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:100
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:103
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:99
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
Definition padstack.h:100
const int accuracy
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:88
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:97
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:108
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:98
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:96
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695