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 (C) 2019-2022, 2024 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 <wx/log.h>
34
36{
37 if( !m_valid )
38 return 0;
39
40 switch( m_parent->Type() )
41 {
42 case PCB_TRACE_T:
43 case PCB_ARC_T:
44 return 2; // start and end
45
46 case PCB_SHAPE_T:
47 return m_anchors.size();
48
49 default:
50 return 1;
51 }
52}
53
54
55const VECTOR2I CN_ITEM::GetAnchor( int n ) const
56{
57 if( !m_valid )
58 return VECTOR2I();
59
60 switch( m_parent->Type() )
61 {
62 case PCB_PAD_T:
63 return static_cast<PAD*>( m_parent )->GetPosition();
64
65 case PCB_TRACE_T:
66 case PCB_ARC_T:
67 if( n == 0 )
68 return static_cast<const PCB_TRACK*>( m_parent )->GetStart();
69 else
70 return static_cast<const PCB_TRACK*>( m_parent )->GetEnd();
71
72 case PCB_VIA_T:
73 return static_cast<const PCB_VIA*>( m_parent )->GetStart();
74
75 case PCB_SHAPE_T:
76 return ( n < static_cast<int>( m_anchors.size() ) ) ? m_anchors[n]->Pos() : VECTOR2I();
77
78 default:
80 return VECTOR2I();
81 }
82}
83
84
86{
87 wxLogDebug( " valid: %d, connected: \n", !!Valid() );
88
89 for( CN_ITEM* i : m_connected )
90 {
91 PCB_TRACK* t = static_cast<PCB_TRACK*>( i->Parent() );
92 wxLogDebug( wxT( " - %p %d\n" ), t, t->Type() );
93 }
94}
95
96
98{
99 if( !Valid() )
100 return 0;
101
102 const ZONE* zone = static_cast<const ZONE*>( Parent() );
103
104 return zone->GetFilledPolysList( m_layer )->COutline( m_subpolyIndex ).PointCount() ? 1 : 0;
105}
106
107
109{
110 if( !Valid() )
111 return VECTOR2I();
112
113 const ZONE* zone = static_cast<const ZONE*>( Parent() );
114
115 return zone->GetFilledPolysList( m_layer )->COutline( m_subpolyIndex ).CPoint( 0 );
116}
117
118
120{
121 int count = 0;
122
123 for( CN_ITEM* item : ConnectedItems() )
124 {
125 if( item->Valid() )
126 count++;
127
128 if( count > 1 )
129 break;
130 }
131
132 return count == 1;
133}
134
135
137{
138 for( auto it = m_connected.begin(); it != m_connected.end(); /* increment in loop */ )
139 {
140 if( !(*it)->Valid() )
141 it = m_connected.erase( it );
142 else
143 ++it;
144 }
145}
146
147
149{
150 if( !pad->IsOnCopperLayer() )
151 return nullptr;
152
153 auto item = new CN_ITEM( pad, false, 1 );
154
155 std::set<VECTOR2I> uniqueAnchors;
156 pad->Padstack().ForEachUniqueLayer(
157 [&]( PCB_LAYER_ID aLayer )
158 {
159 uniqueAnchors.insert( pad->ShapePos( aLayer ) );
160 } );
161
162 for( const VECTOR2I& anchor : uniqueAnchors )
163 item->AddAnchor( anchor );
164
165 item->SetLayers( F_Cu, B_Cu );
166
167 switch( pad->GetAttribute() )
168 {
169 case PAD_ATTRIB::SMD:
170 case PAD_ATTRIB::NPTH:
171 case PAD_ATTRIB::CONN:
172 {
173 LSEQ lmsk = pad->GetLayerSet().CuStack();
174
175 if( !lmsk.empty() )
176 item->SetLayer( lmsk.front() );
177
178 break;
179 }
180 default:
181 break;
182 }
183
184 addItemtoTree( item );
185 m_items.push_back( item );
186 SetDirty();
187 return item;
188}
189
190
192{
193 CN_ITEM* item = new CN_ITEM( track, true );
194 m_items.push_back( item );
195 item->AddAnchor( track->GetStart() );
196 item->AddAnchor( track->GetEnd() );
197 item->SetLayer( track->GetLayer() );
198 addItemtoTree( item );
199 SetDirty();
200 return item;
201}
202
203
205{
206 CN_ITEM* item = new CN_ITEM( aArc, true );
207 m_items.push_back( item );
208 item->AddAnchor( aArc->GetStart() );
209 item->AddAnchor( aArc->GetEnd() );
210 item->SetLayer( aArc->GetLayer() );
211 addItemtoTree( item );
212 SetDirty();
213 return item;
214}
215
216
218{
219 CN_ITEM* item = new CN_ITEM( via, !via->GetIsFree(), 1 );
220
221 m_items.push_back( item );
222 item->AddAnchor( via->GetStart() );
223
224 item->SetLayers( via->TopLayer(), via->BottomLayer() );
225 addItemtoTree( item );
226 SetDirty();
227 return item;
228}
229
230
231const std::vector<CN_ITEM*> CN_LIST::Add( ZONE* zone, PCB_LAYER_ID aLayer )
232{
233 const std::shared_ptr<SHAPE_POLY_SET>& polys = zone->GetFilledPolysList( aLayer );
234
235 std::vector<CN_ITEM*> rv;
236
237 for( int j = 0; j < polys->OutlineCount(); j++ )
238 {
239 CN_ZONE_LAYER* zitem = new CN_ZONE_LAYER( zone, aLayer, j );
240
241 zitem->BuildRTree();
242
243 for( const VECTOR2I& pt : zone->GetFilledPolysList( aLayer )->COutline( j ).CPoints() )
244 zitem->AddAnchor( pt );
245
246 rv.push_back( Add( zitem ) );
247 }
248
249 return rv;
250}
251
252
254{
255 m_items.push_back( zitem );
256 addItemtoTree( zitem );
257 SetDirty();
258 return zitem;
259}
260
261
263{
264 CN_ITEM* item = new CN_ITEM( shape, true );
265 m_items.push_back( item );
266
267 for( const VECTOR2I& point : shape->GetConnectionPoints() )
268 item->AddAnchor( point );
269
270 item->SetLayer( shape->GetLayer() );
271 addItemtoTree( item );
272 SetDirty();
273 return item;
274}
275
276
277void CN_LIST::RemoveInvalidItems( std::vector<CN_ITEM*>& aGarbage )
278{
279 if( !m_hasInvalid )
280 return;
281
282 auto lastItem = std::remove_if( m_items.begin(), m_items.end(),
283 [&aGarbage]( CN_ITEM* item )
284 {
285 if( !item->Valid() )
286 {
287 aGarbage.push_back ( item );
288 return true;
289 }
290
291 return false;
292 } );
293
294 m_items.resize( lastItem - m_items.begin() );
295
296 for( CN_ITEM* item : aGarbage )
297 m_index.Remove( item );
298
299 m_hasInvalid = false;
300}
301
302
304{
305 assert( m_item->Valid() );
306 return m_item->Parent();
307}
308
309
311{
312 if( !m_item )
313 return false;
314
315 return m_item->Valid();
316}
317
318
320{
321 return !Valid() || m_item->Dirty();
322}
323
324
326{
327 int accuracy = 0;
328
329 if( !m_cluster )
330 return true;
331
332 // the minimal number of items connected to item_ref
333 // at this anchor point to decide the anchor is *not* dangling
334 size_t minimal_count = 1;
335 size_t connected_count = m_item->ConnectedItems().size();
336
337 // a via can be removed if connected to only one other item.
338 if( Parent()->Type() == PCB_VIA_T )
339 return connected_count < 2;
340
341 if( m_item->AnchorCount() == 1 )
342 return connected_count < minimal_count;
343
344 if( Parent()->Type() == PCB_TRACE_T || Parent()->Type() == PCB_ARC_T )
345 {
346 accuracy = KiROUND( static_cast<const PCB_TRACK*>( Parent() )->GetWidth() / 2 );
347 }
348 else if( Parent()->Type() == PCB_SHAPE_T )
349 {
350 auto shape = static_cast<const PCB_SHAPE*>( Parent() );
351
352 if( !shape->IsFilled() )
353 accuracy = KiROUND( shape->GetWidth() / 2 );
354 }
355
356 // Items with multiple anchors have usually items connected to each anchor.
357 // We want only the item count of this anchor point
358 connected_count = 0;
359
360 for( CN_ITEM* item : m_item->ConnectedItems() )
361 {
362 if( item->Parent()->Type() == PCB_ZONE_T )
363 {
364 ZONE* zone = static_cast<ZONE*>( item->Parent() );
365
366 if( zone->HitTestFilledArea( item->GetBoardLayer(), Pos(), accuracy ) )
367 connected_count++;
368 }
369 else if( item->Parent()->HitTest( Pos(), accuracy ) )
370 {
371 connected_count++;
372 }
373 }
374
375 return connected_count < minimal_count;
376}
377
378
380{
381 if( !m_cluster )
382 return 0;
383
384 int connected_count = 0;
385
386 for( CN_ITEM* item : m_item->ConnectedItems() )
387 {
388 if( item->Parent()->Type() == PCB_ZONE_T )
389 {
390 ZONE* zone = static_cast<ZONE*>( item->Parent() );
391
392 if( zone->HitTestFilledArea( item->GetBoardLayer(), Pos() ) )
393 connected_count++;
394 }
395 else if( item->Parent()->HitTest( Pos() ) )
396 {
397 connected_count++;
398 }
399 }
400
401 return connected_count;
402}
403
404
406{
407 m_items.reserve( 64 );
408 m_originPad = nullptr;
409 m_originNet = -1;
410 m_conflicting = false;
411}
412
413
415{
416}
417
418
420{
421 if( !m_originPad || !m_originPad->Valid() )
422 return "<none>";
423 else
424 return m_originPad->Parent()->GetNetname();
425}
426
427
428bool CN_CLUSTER::Contains( const CN_ITEM* aItem )
429{
430 return alg::contains( m_items, aItem );
431}
432
433
435{
436 return std::find_if( m_items.begin(), m_items.end(),
437 [&aItem]( const CN_ITEM* item )
438 {
439 return item->Valid() && item->Parent() == aItem;
440 } ) != m_items.end();
441}
442
443
445{
446 for( CN_ITEM* item : m_items )
447 {
448 wxLogTrace( wxT( "CN" ), wxT( " - item : %p bitem : %p type : %d inet %s\n" ),
449 item,
450 item->Parent(),
451 item->Parent()->Type(),
452 (const char*) item->Parent()->GetNetname().c_str() );
453 wxLogTrace( wxT( "CN" ), wxT( "- item : %p bitem : %p type : %d inet %s\n" ),
454 item,
455 item->Parent(),
456 item->Parent()->Type(),
457 (const char*) item->Parent()->GetNetname().c_str() );
458 item->Dump();
459 }
460}
461
462
464{
465 m_items.push_back( item );
466
467 int netCode = item->Net();
468
469 if( netCode <= 0 )
470 return;
471
472 if( m_originNet <= 0 )
473 {
474 m_originNet = netCode;
476 }
477
478 if( item->Parent()->Type() == PCB_PAD_T && !static_cast<PAD*>( item->Parent() )->IsFreePad() )
479 {
480 int rank;
481 auto it = m_netRanks.find( netCode );
482
483 if( it == m_netRanks.end() )
484 {
485 m_netRanks[netCode] = 1;
486 rank = 1;
487 }
488 else
489 {
490 it->second++;
491 rank = it->second;
492 }
493
494 if( !m_originPad || rank > m_netRanks[m_originNet] )
495 {
496 m_originPad = item;
497 m_originNet = netCode;
498 }
499
500 if( m_originPad && item->Net() != m_originNet )
501 m_conflicting = true;
502 }
503}
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,...
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:237
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 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
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
virtual const VECTOR2I GetAnchor(int n) const override
PCB_LAYER_ID m_layer
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
virtual wxString GetClass() const =0
Return the class name.
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: lseq.h:47
Definition: pad.h:54
bool IsFreePad() const
Definition: pad.cpp:262
std::vector< VECTOR2I > GetConnectionPoints() const
Definition: pcb_shape.cpp:248
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: pcb_shape.h:69
const VECTOR2I & GetStart() const
Definition: pcb_track.h:122
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:119
Handle a list of polygons defining a copper zone.
Definition: zone.h:73
const std::shared_ptr< SHAPE_POLY_SET > & GetFilledPolysList(PCB_LAYER_ID aLayer) const
Definition: zone.h:620
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:720
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
@ 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:107
@ 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:691