/* * 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 * * 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 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( m_parent )->ShapePos(); break; case PCB_TRACE_T: { auto tr = static_cast( m_parent ); return ( n == 0 ? tr->GetStart() : tr->GetEnd() ); break; } case PCB_VIA_T: return static_cast( 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( i->Parent() ); printf( " - %p %d\n", t, t->Type() ); } } int CN_ZONE::AnchorCount() const { if( !Valid() ) return 0; const auto zone = static_cast( 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 ( 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_LIST::Add( ZONE_CONTAINER* zone ) { const auto& polys = zone->GetFilledPolysList(); std::vector 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& 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 ""; 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; } } }