KiCad PCB EDA Suite
connectivity_items.cpp
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) 2016-2018 CERN
5  * Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
28 
30 {
31  if( !m_valid )
32  return 0;
33 
34  switch( m_parent->Type() )
35  {
36  case PCB_PAD_T:
37  return 5; // center, north, south, east and west
38  case PCB_TRACE_T:
39  return 2; // stard and end
40  default:
41  return 1;
42  }
43 }
44 
45 
46 const VECTOR2I CN_ITEM::GetAnchor( int n ) const
47 {
48  VECTOR2I pt0;
49 
50  if( !m_valid )
51  return pt0;
52 
53  switch( m_parent->Type() )
54  {
55  case PCB_PAD_T:
56  {
57  D_PAD* pad = (D_PAD*) m_parent;
58 
59  if( n == 0 )
60  return VECTOR2I( pad->GetPosition() );
61 
62  // ShapePos() is the geometric center (not anchor) for the pad
63  pt0 = pad->ShapePos();
64  VECTOR2I pt1 = pt0;
65 
66  switch( n )
67  {
68  case 1: pt1.y = m_bbox.GetTop(); break; // North
69  case 2: pt1.y = m_bbox.GetBottom(); break; // South
70  case 3: pt1.x = m_bbox.GetLeft(); break; // East
71  case 4: pt1.x = m_bbox.GetRight(); break; // West
72  default: break; // Wicked witch
73  }
74 
75  switch( pad->GetShape() )
76  {
77  case PAD_SHAPE_RECT:
78  case PAD_SHAPE_OVAL:
81  return pt1;
82 
83  case PAD_SHAPE_CIRCLE:
84  // Thermal spokes on circular pads form an 'X' instead of a '+'
85  RotatePoint( pt1, pad->ShapePos(), 450 );
86  return pt1;
87 
89  case PAD_SHAPE_CUSTOM:
90  {
91  SHAPE_POLY_SET padPolySet;
92  pad->BuildPadShapePolygon( padPolySet, wxSize( 0, 0 ), ARC_LOW_DEF );
93  const SHAPE_LINE_CHAIN& padOutline = padPolySet.COutline( 0 );
94  SHAPE_LINE_CHAIN::INTERSECTIONS intersections;
95 
96  padOutline.Intersect( SEG( pt0, pt1 ), intersections );
97 
98  if( intersections.empty() )
99  {
100  // There should always be at least some copper outside the hole
101  assert( false );
102  return pt0;
103  }
104 
105  return intersections[ intersections.size() - 1 ].p;
106  }
107  }
108 
109  break;
110  }
111  case PCB_TRACE_T:
112  if( n == 0 )
113  return static_cast<const TRACK*>( m_parent )->GetStart();
114  else
115  return static_cast<const TRACK*>( m_parent )->GetEnd();
116 
117  case PCB_VIA_T:
118  return static_cast<const VIA*>( m_parent )->GetStart();
119 
120  default:
121  assert( false );
122  break;
123  }
124 
125  return pt0;
126 }
127 
128 
129 int CN_ITEM::Net() const
130 {
131  if( !m_parent || !m_valid )
132  return -1;
133 
134  return m_parent->GetNetCode();
135 }
136 
137 
139 {
140  printf(" valid: %d, connected: \n", !!Valid());
141 
142  for( auto i : m_connected )
143  {
144  TRACK* t = static_cast<TRACK*>( i->Parent() );
145  printf( " - %p %d\n", t, t->Type() );
146  }
147 }
148 
149 
151 {
152  if( !Valid() )
153  return 0;
154 
155  const auto zone = static_cast<const ZONE_CONTAINER*>( Parent() );
156  const auto& outline = zone->GetFilledPolysList().COutline( m_subpolyIndex );
157 
158  return outline.PointCount() ? 1 : 0;
159 }
160 
161 
162 const VECTOR2I CN_ZONE::GetAnchor( int n ) const
163 {
164  if( !Valid() )
165  return VECTOR2I();
166 
167  const auto zone = static_cast<const ZONE_CONTAINER*> ( Parent() );
168  const auto& outline = zone->GetFilledPolysList().COutline( m_subpolyIndex );
169 
170  return outline.CPoint( 0 );
171 }
172 
173 
175 {
176  for( auto it = m_connected.begin(); it != m_connected.end(); )
177  {
178  if( !(*it)->Valid() )
179  it = m_connected.erase( it );
180  else
181  ++it;
182  }
183 }
184 
185 
187  {
188  if( !pad->IsOnCopperLayer() )
189  return nullptr;
190 
191  auto item = new CN_ITEM( pad, false, 1 );
192  item->AddAnchor( pad->ShapePos() );
193  item->SetLayers( LAYER_RANGE( F_Cu, B_Cu ) );
194 
195  switch( pad->GetAttribute() )
196  {
197  case PAD_ATTRIB_SMD:
199  case PAD_ATTRIB_CONN:
200  {
201  LSET lmsk = pad->GetLayerSet();
202 
203  for( int i = 0; i <= MAX_CU_LAYERS; i++ )
204  {
205  if( lmsk[i] )
206  {
207  item->SetLayer( i );
208  break;
209  }
210  }
211  break;
212  }
213  default:
214  break;
215  }
216 
217  addItemtoTree( item );
218  m_items.push_back( item );
219  SetDirty();
220  return item;
221 }
222 
224  {
225  auto item = new CN_ITEM( track, true );
226  m_items.push_back( item );
227  item->AddAnchor( track->GetStart() );
228  item->AddAnchor( track->GetEnd() );
229  item->SetLayer( track->GetLayer() );
230  addItemtoTree( item );
231  SetDirty();
232  return item;
233  }
234 
236  {
237  auto item = new CN_ITEM( via, true, 1 );
238 
239  m_items.push_back( item );
240  item->AddAnchor( via->GetStart() );
241  item->SetLayers( LAYER_RANGE( F_Cu, B_Cu ) );
242  addItemtoTree( item );
243  SetDirty();
244  return item;
245  }
246 
247  const std::vector<CN_ITEM*> CN_LIST::Add( ZONE_CONTAINER* zone )
248  {
249  const auto& polys = zone->GetFilledPolysList();
250 
251  std::vector<CN_ITEM*> rv;
252 
253  for( int j = 0; j < polys.OutlineCount(); j++ )
254  {
255  CN_ZONE* zitem = new CN_ZONE( zone, false, j );
256  const auto& outline = zone->GetFilledPolysList().COutline( j );
257 
258  for( int k = 0; k < outline.PointCount(); k++ )
259  zitem->AddAnchor( outline.CPoint( k ) );
260 
261  m_items.push_back( zitem );
262  zitem->SetLayer( zone->GetLayer() );
263  addItemtoTree( zitem );
264  rv.push_back( zitem );
265  SetDirty();
266  }
267 
268  return rv;
269  }
270 
271 
272 void CN_LIST::RemoveInvalidItems( std::vector<CN_ITEM*>& aGarbage )
273 {
274  if( !m_hasInvalid )
275  return;
276 
277  auto lastItem = std::remove_if(m_items.begin(), m_items.end(), [&aGarbage] ( CN_ITEM* item )
278  {
279  if( !item->Valid() )
280  {
281  aGarbage.push_back ( item );
282  return true;
283  }
284 
285  return false;
286  } );
287 
288  m_items.resize( lastItem - m_items.begin() );
289 
290  for( auto item : m_items )
291  item->RemoveInvalidRefs();
292 
293  for( auto item : aGarbage )
294  m_index.Remove( item );
295 
296  m_hasInvalid = false;
297 }
298 
299 
301 {
302  assert( m_item->Valid() );
303  return m_item->Parent();
304 }
305 
306 
307 bool CN_ANCHOR::Valid() const
308 {
309  if( !m_item )
310  return false;
311 
312  return m_item->Valid();
313 }
314 
315 
317 {
318  if( !m_cluster )
319  return true;
320 
321  // the minimal number of items connected to item_ref
322  // at this anchor point to decide the anchor is *not* dangling
323  size_t minimal_count = 1;
324  size_t connected_count = m_item->ConnectedItems().size();
325 
326  // a via can be removed if connected to only one other item.
327  if( Parent()->Type() == PCB_VIA_T )
328  return connected_count < 2;
329 
330  if( m_item->AnchorCount() == 1 )
331  return connected_count < minimal_count;
332 
333  // Items with multiple anchors have usually items connected to each anchor.
334  // We want only the item count of this anchor point
335  connected_count = 0;
336  for( auto item : m_item->ConnectedItems() )
337  {
338  if( item->Parent()->Type() == PCB_ZONE_AREA_T )
339  {
340  ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item->Parent() );
341 
342  if( zone->HitTestFilledArea( wxPoint( Pos().x, Pos().y ) ) )
343  connected_count++;
344  }
345  else if( item->Parent()->HitTest( wxPoint( Pos().x, Pos().y ) ) )
346  connected_count++;
347  }
348 
349  return connected_count < minimal_count;
350 }
351 
352 
354 {
355  if( !m_cluster )
356  return 0;
357 
358  int connected_count = 0;
359 
360  for( auto item : m_item->ConnectedItems() )
361  {
362  if( item->Parent()->Type() == PCB_ZONE_AREA_T )
363  {
364  ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item->Parent() );
365 
366  if( zone->HitTestFilledArea( wxPoint( Pos().x, Pos().y ) ) )
367  connected_count++;
368  }
369  else if( item->Parent()->HitTest( wxPoint( Pos().x, Pos().y ) ) )
370  connected_count++;
371  }
372 
373  return connected_count;
374 }
375 
376 
378 {
379  m_items.reserve( 64 );
380  m_originPad = nullptr;
381  m_originNet = -1;
382  m_conflicting = false;
383 }
384 
385 
387 {
388 }
389 
390 
392 {
393  if( !m_originPad || !m_originPad->Valid() )
394  return "<none>";
395  else
396  return m_originPad->Parent()->GetNetname();
397 }
398 
399 
400 bool CN_CLUSTER::Contains( const CN_ITEM* aItem )
401 {
402  return std::find( m_items.begin(), m_items.end(), aItem ) != m_items.end();
403 }
404 
405 
407 {
408  return std::find_if( m_items.begin(), m_items.end(), [ &aItem ] ( const CN_ITEM* item )
409  { return item->Valid() && item->Parent() == aItem; } ) != m_items.end();
410 }
411 
412 
414 {
415  for( auto item : m_items )
416  {
417  wxLogTrace( "CN", " - item : %p bitem : %p type : %d inet %s\n", item, item->Parent(),
418  item->Parent()->Type(), (const char*) item->Parent()->GetNetname().c_str() );
419  printf( "- item : %p bitem : %p type : %d inet %s\n", item, item->Parent(),
420  item->Parent()->Type(), (const char*) item->Parent()->GetNetname().c_str() );
421  item->Dump();
422  }
423 }
424 
425 
427 {
428  m_items.push_back( item );
429 
430  if( item->Net() <= 0 )
431  return;
432 
433  if( m_originNet <= 0 )
434  {
435  m_originNet = item->Net();
436  }
437 
438  if( item->Parent()->Type() == PCB_PAD_T )
439  {
440  if( !m_originPad )
441  {
442  m_originPad = item;
443  m_originNet = item->Net();
444  }
445 
446  if( m_originPad && item->Net() != m_originNet )
447  {
448  m_conflicting = true;
449  }
450  }
451 }
void RemoveInvalidItems(std::vector< CN_ITEM * > &aGarbage)
const CONNECTED_ITEMS & ConnectedItems() const
bool Contains(const CN_ITEM *aItem)
virtual int AnchorCount() const override
std::vector< CN_ITEM * > m_items
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:57
int Intersect(const SEG &aSeg, INTERSECTIONS &aIp) const
Function Intersect()
int GetNetCode() const
Function GetNetCode.
std::vector< INTERSECTION > INTERSECTIONS
BOARD_CONNECTED_ITEM * m_parent
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:66
coord_type GetTop() const
Definition: box2.h:202
std::shared_ptr< CN_CLUSTER > m_cluster
Cluster to which the anchor belongs.
const wxPoint & GetStart() const
Definition: class_track.h:109
void addItemtoTree(CN_ITEM *item)
bool m_valid
valid flag, used to identify garbage items (we use lazy removal)
CN_ITEM * Add(D_PAD *pad)
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:62
class ZONE_CONTAINER, a zone area
Definition: typeinfo.h:100
virtual PCB_LAYER_ID GetLayer() const override
Function GetLayer returns the primary layer this item is on.
Definition: class_zone.cpp:190
void BuildPadShapePolygon(SHAPE_POLY_SET &aCornerBuffer, wxSize aInflateValue, int aError=ARC_HIGH_DEF) const
Function BuildPadShapePolygon Build the Corner list of the polygonal shape, depending on shape,...
coord_type GetRight() const
Definition: box2.h:197
bool HitTestFilledArea(const wxPoint &aRefPos) const
Function HitTestFilledArea tests if the given wxPoint is within the bounds of a filled area of this z...
Definition: class_zone.cpp:655
class D_PAD, a pad in a footprint
Definition: typeinfo.h:90
BOARD_CONNECTED_ITEM * Parent() const
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:206
coord_type GetBottom() const
Definition: box2.h:198
bool IsDangling() const
has meaning only for tracks and vias.
VECTOR2< int > VECTOR2I
Definition: vector2d.h:587
Class BOARD_CONNECTED_ITEM is a base class derived from BOARD_ITEM for items that can be connected an...
void SetDirty(bool aDirty=true)
int ConnectedItemsCount() const
has meaning only for tracks and vias.
int Net() const
PAD_ATTR_T GetAttribute() const
Definition: class_pad.h:429
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
virtual int AnchorCount() const
std::vector< CN_ITEM * > m_items
Class LSET is a set of PCB_LAYER_IDs.
Class SHAPE_POLY_SET.
bool IsOnCopperLayer() const override
Definition: class_pad.h:269
LSET GetLayerSet() const override
Function GetLayerSet returns a "layer mask", which is a bitmap of all layers on which the TRACK segme...
Definition: class_pad.h:426
BOX2I m_bbox
bounding box for the item
void Add(CN_ITEM *item)
const wxString & GetNetname() const
Function GetNetname.
Like smd, does not appear on the solder paste layer (default) note also has a special attribute in Ge...
Definition: pad_shapes.h:63
bool Valid() const
virtual const VECTOR2I GetAnchor(int n) const
Definition: seg.h:36
wxString OriginNetName() const
void AddAnchor(const VECTOR2I &aPos)
virtual const VECTOR2I GetAnchor(int n) const override
CN_ITEM * m_item
Item owning the anchor.
Class SHAPE_LINE_CHAIN.
void SetLayer(int aLayer)
Function SetLayer()
CN_ITEM * m_originPad
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
size_t i
Definition: json11.cpp:597
wxPoint ShapePos() const
Definition: class_pad.cpp:570
BOARD_CONNECTED_ITEM * Parent() const
const wxPoint & GetEnd() const
Definition: class_track.h:106
void Remove(T aItem)
Function Remove() Removes an item from the tree.
const VECTOR2I & Pos() const
CONNECTED_ITEMS m_connected
list of items physically connected (touching)
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
PAD_SHAPE_T GetShape() const
Function GetShape.
Definition: class_pad.h:221
coord_type GetLeft() const
Definition: box2.h:201
const wxPoint GetPosition() const override
Definition: class_pad.h:225
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
Class LAYER_RANGE.
Definition: pns_layerset.h:32
void RemoveInvalidRefs()
bool Valid() const
CN_RTREE< CN_ITEM * > m_index
KICAD_T Type() const
Function Type()
Definition: base_struct.h:210
const SHAPE_POLY_SET & GetFilledPolysList() const
Function GetFilledPolysList returns a reference to the list of filled polygons.
Definition: class_zone.h:543