You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							351 lines
						
					
					
						
							8.1 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							351 lines
						
					
					
						
							8.1 KiB
						
					
					
				| /* | |
|  * This program source code file is part of KICAD, a free EDA CAD application. | |
|  * | |
|  * Copyright (C) 2016-2018 CERN | |
|  * Copyright (C) 2018  KiCad Developers, see AUTHORS.txt for contributors. | |
|  * | |
|  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch> | |
|  * | |
|  * This program is free software; you can redistribute it and/or | |
|  * modify it under the terms of the GNU General Public License | |
|  * as published by the Free Software Foundation; either version 2 | |
|  * of the License, or (at your option) any later version. | |
|  * | |
|  * This program is distributed in the hope that it will be useful, | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |
|  * GNU General Public License for more details. | |
|  * | |
|  * You should have received a copy of the GNU General Public License | |
|  * along with this program; if not, you may find one here: | |
|  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html | |
|  * or you may search the http://www.gnu.org website for the version 2 license, | |
|  * or you may write to the Free Software Foundation, Inc., | |
|  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA | |
|  */ | |
| 
 | |
| #include <connectivity/connectivity_items.h> | |
|  | |
| int CN_ITEM::AnchorCount() const | |
| { | |
|     if( !m_valid ) | |
|         return 0; | |
| 
 | |
|     return m_parent->Type() == PCB_TRACE_T ? 2 : 1; | |
| } | |
| 
 | |
| 
 | |
| const VECTOR2I CN_ITEM::GetAnchor( int n ) const | |
| { | |
|     if( !m_valid ) | |
|         return VECTOR2I(); | |
| 
 | |
|     switch( m_parent->Type() ) | |
|     { | |
|         case PCB_PAD_T: | |
|             return static_cast<const D_PAD*>( m_parent )->ShapePos(); | |
|             break; | |
| 
 | |
|         case PCB_TRACE_T: | |
|         { | |
|             auto tr = static_cast<const TRACK*>( m_parent ); | |
|             return ( n == 0 ? tr->GetStart() : tr->GetEnd() ); | |
| 
 | |
|             break; | |
|         } | |
| 
 | |
|         case PCB_VIA_T: | |
|             return static_cast<const VIA*>( m_parent )->GetStart(); | |
| 
 | |
|         default: | |
|             assert( false ); | |
|             return VECTOR2I(); | |
|     } | |
| } | |
| 
 | |
| 
 | |
| int CN_ITEM::Net() const | |
| { | |
|     if( !m_parent || !m_valid ) | |
|         return -1; | |
| 
 | |
|     return m_parent->GetNetCode(); | |
| } | |
| 
 | |
| 
 | |
| void CN_ITEM::Dump() | |
| { | |
|     printf("    valid: %d, connected: \n", !!Valid()); | |
| 
 | |
|     for( auto i : m_connected ) | |
|     { | |
|         TRACK* t = static_cast<TRACK*>( i->Parent() ); | |
|         printf( "    - %p %d\n", t, t->Type() ); | |
|     } | |
| } | |
| 
 | |
| 
 | |
| int CN_ZONE::AnchorCount() const | |
| { | |
|     if( !Valid() ) | |
|         return 0; | |
| 
 | |
|     const auto zone = static_cast<const ZONE_CONTAINER*>( Parent() ); | |
|     const auto& outline = zone->GetFilledPolysList().COutline( m_subpolyIndex ); | |
| 
 | |
|     return outline.PointCount() ? 1 : 0; | |
| } | |
| 
 | |
| 
 | |
| const VECTOR2I CN_ZONE::GetAnchor( int n ) const | |
| { | |
|     if( !Valid() ) | |
|         return VECTOR2I(); | |
| 
 | |
|     const auto zone = static_cast<const ZONE_CONTAINER*> ( Parent() ); | |
|     const auto& outline = zone->GetFilledPolysList().COutline( m_subpolyIndex ); | |
| 
 | |
|     return outline.CPoint( 0 ); | |
| } | |
| 
 | |
| 
 | |
| void CN_ITEM::RemoveInvalidRefs() | |
| { | |
|     for( auto it = m_connected.begin(); it != m_connected.end(); ) | |
|     { | |
|         if( !(*it)->Valid() ) | |
|             it = m_connected.erase( it ); | |
|         else | |
|             ++it; | |
|     } | |
| } | |
| 
 | |
| 
 | |
| CN_ITEM* CN_LIST::Add( D_PAD* pad ) | |
|  { | |
|      auto item = new CN_ITEM( pad, false, 1 ); | |
|      item->AddAnchor( pad->ShapePos() ); | |
|      item->SetLayers( LAYER_RANGE( F_Cu, B_Cu ) ); | |
| 
 | |
|      switch( pad->GetAttribute() ) | |
|      { | |
|      case PAD_ATTRIB_SMD: | |
|      case PAD_ATTRIB_HOLE_NOT_PLATED: | |
|      case PAD_ATTRIB_CONN: | |
|      { | |
|          LSET lmsk = pad->GetLayerSet(); | |
| 
 | |
|          for( int i = 0; i <= MAX_CU_LAYERS; i++ ) | |
|          { | |
|              if( lmsk[i] ) | |
|              { | |
|                  item->SetLayer( i ); | |
|                  break; | |
|              } | |
|          } | |
|          break; | |
|      } | |
|      default: | |
|          break; | |
|      } | |
| 
 | |
|      addItemtoTree( item ); | |
|      m_items.push_back( item ); | |
|      SetDirty(); | |
|      return item; | |
|  } | |
| 
 | |
|  CN_ITEM* CN_LIST::Add( TRACK* track ) | |
|  { | |
|      auto item = new CN_ITEM( track, true ); | |
|      m_items.push_back( item ); | |
|      item->AddAnchor( track->GetStart() ); | |
|      item->AddAnchor( track->GetEnd() ); | |
|      item->SetLayer( track->GetLayer() ); | |
|      addItemtoTree( item ); | |
|      SetDirty(); | |
|      return item; | |
|  } | |
| 
 | |
|  CN_ITEM* CN_LIST::Add( VIA* via ) | |
|  { | |
|      auto item = new CN_ITEM( via, true, 1 ); | |
| 
 | |
|      m_items.push_back( item ); | |
|      item->AddAnchor( via->GetStart() ); | |
|      item->SetLayers( LAYER_RANGE( F_Cu, B_Cu ) ); | |
|      addItemtoTree( item ); | |
|      SetDirty(); | |
|      return item; | |
|  } | |
| 
 | |
|  const std::vector<CN_ITEM*> CN_LIST::Add( ZONE_CONTAINER* zone ) | |
|  { | |
|      const auto& polys = zone->GetFilledPolysList(); | |
| 
 | |
|      std::vector<CN_ITEM*> rv; | |
| 
 | |
|      for( int j = 0; j < polys.OutlineCount(); j++ ) | |
|      { | |
|          CN_ZONE* zitem = new CN_ZONE( zone, false, j ); | |
|          const auto& outline = zone->GetFilledPolysList().COutline( j ); | |
| 
 | |
|          for( int k = 0; k < outline.PointCount(); k++ ) | |
|              zitem->AddAnchor( outline.CPoint( k ) ); | |
| 
 | |
|          m_items.push_back( zitem ); | |
|          zitem->SetLayer( zone->GetLayer() ); | |
|          addItemtoTree( zitem ); | |
|          rv.push_back( zitem ); | |
|          SetDirty(); | |
|      } | |
| 
 | |
|      return rv; | |
|  } | |
| 
 | |
| 
 | |
| void CN_LIST::RemoveInvalidItems( std::vector<CN_ITEM*>& aGarbage ) | |
| { | |
|     if( !m_hasInvalid ) | |
|         return; | |
| 
 | |
|     auto lastItem = std::remove_if(m_items.begin(), m_items.end(), [&aGarbage] ( CN_ITEM* item ) | |
|     { | |
|         if( !item->Valid() ) | |
|         { | |
|             aGarbage.push_back ( item ); | |
|             return true; | |
|         } | |
| 
 | |
|         return false; | |
|     } ); | |
| 
 | |
|     m_items.resize( lastItem - m_items.begin() ); | |
| 
 | |
|     for( auto item : m_items ) | |
|         item->RemoveInvalidRefs(); | |
| 
 | |
|     for( auto item : aGarbage ) | |
|         m_index.Remove( item ); | |
| 
 | |
|     m_hasInvalid = false; | |
| } | |
| 
 | |
| 
 | |
| BOARD_CONNECTED_ITEM* CN_ANCHOR::Parent() const | |
| { | |
|     assert( m_item->Valid() ); | |
|     return m_item->Parent(); | |
| } | |
| 
 | |
| 
 | |
| bool CN_ANCHOR::Valid() const | |
| { | |
|     if( !m_item ) | |
|         return false; | |
| 
 | |
|     return m_item->Valid(); | |
| } | |
| 
 | |
| 
 | |
| bool CN_ANCHOR::IsDangling() const | |
| { | |
|     if( !m_cluster ) | |
|         return true; | |
| 
 | |
|     // the minimal number of items connected to item_ref | |
|     // at this anchor point to decide the anchor is *not* dangling | |
|     size_t minimal_count = 1; | |
|     size_t connected_count = m_item->ConnectedItems().size(); | |
| 
 | |
|     // a via can be removed if connected to only one other item. | |
|     if( Parent()->Type() == PCB_VIA_T ) | |
|         return connected_count < 2; | |
| 
 | |
|     if( m_item->AnchorCount() == 1 ) | |
|         return connected_count < minimal_count; | |
| 
 | |
|     // Only items with multiple anchors might have additional items connected that we | |
|     // should ignore for this calculation. | |
|     for( auto item : m_item->ConnectedItems() ) | |
|     { | |
|         if( !item->Parent()->HitTest( wxPoint( Pos().x, Pos().y ) ) ) | |
|             connected_count--; | |
|     } | |
| 
 | |
|     return connected_count < minimal_count; | |
| } | |
| 
 | |
| 
 | |
| CN_CLUSTER::CN_CLUSTER() | |
| { | |
|     m_items.reserve( 64 ); | |
|     m_originPad = nullptr; | |
|     m_originNet = -1; | |
|     m_conflicting = false; | |
| } | |
| 
 | |
| 
 | |
| CN_CLUSTER::~CN_CLUSTER() | |
| { | |
| } | |
| 
 | |
| 
 | |
| wxString CN_CLUSTER::OriginNetName() const | |
| { | |
|     if( !m_originPad || !m_originPad->Valid() ) | |
|         return "<none>"; | |
|     else | |
|         return m_originPad->Parent()->GetNetname(); | |
| } | |
| 
 | |
| 
 | |
| bool CN_CLUSTER::Contains( const CN_ITEM* aItem ) | |
| { | |
|     return std::find( m_items.begin(), m_items.end(), aItem ) != m_items.end(); | |
| } | |
| 
 | |
| 
 | |
| bool CN_CLUSTER::Contains( const BOARD_CONNECTED_ITEM* aItem ) | |
| { | |
|     return std::find_if( m_items.begin(), m_items.end(), [ &aItem ] ( const CN_ITEM* item ) | |
|             { return item->Valid() && item->Parent() == aItem; } ) != m_items.end(); | |
| } | |
| 
 | |
| 
 | |
| void CN_CLUSTER::Dump() | |
| { | |
|     for( auto item : m_items ) | |
|     { | |
|         wxLogTrace( "CN", " - item : %p bitem : %p type : %d inet %s\n", item, item->Parent(), | |
|                 item->Parent()->Type(), (const char*) item->Parent()->GetNetname().c_str() ); | |
|         printf( "- item : %p bitem : %p type : %d inet %s\n", item, item->Parent(), | |
|                         item->Parent()->Type(), (const char*) item->Parent()->GetNetname().c_str() ); | |
|         item->Dump(); | |
|     } | |
| } | |
| 
 | |
| 
 | |
| void CN_CLUSTER::Add( CN_ITEM* item ) | |
| { | |
|     m_items.push_back( item ); | |
| 
 | |
|     if( m_originNet < 0 ) | |
|     { | |
|         m_originNet = item->Net(); | |
|     } | |
| 
 | |
|     if( item->Parent()->Type() == PCB_PAD_T ) | |
|     { | |
|         if( !m_originPad ) | |
|         { | |
|             m_originPad = item; | |
|             m_originNet = item->Net(); | |
|         } | |
| 
 | |
|         if( m_originPad && item->Net() != m_originNet ) | |
|         { | |
|             m_conflicting = true; | |
|         } | |
|     } | |
| }
 |