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

  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) 2018 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. #include <connectivity/connectivity_items.h>
  27. int CN_ITEM::AnchorCount() const
  28. {
  29. if( !m_valid )
  30. return 0;
  31. return m_parent->Type() == PCB_TRACE_T ? 2 : 1;
  32. }
  33. const VECTOR2I CN_ITEM::GetAnchor( int n ) const
  34. {
  35. if( !m_valid )
  36. return VECTOR2I();
  37. switch( m_parent->Type() )
  38. {
  39. case PCB_PAD_T:
  40. return static_cast<const D_PAD*>( m_parent )->ShapePos();
  41. break;
  42. case PCB_TRACE_T:
  43. {
  44. auto tr = static_cast<const TRACK*>( m_parent );
  45. return ( n == 0 ? tr->GetStart() : tr->GetEnd() );
  46. break;
  47. }
  48. case PCB_VIA_T:
  49. return static_cast<const VIA*>( m_parent )->GetStart();
  50. default:
  51. assert( false );
  52. return VECTOR2I();
  53. }
  54. }
  55. int CN_ITEM::Net() const
  56. {
  57. if( !m_parent || !m_valid )
  58. return -1;
  59. return m_parent->GetNetCode();
  60. }
  61. void CN_ITEM::Dump()
  62. {
  63. printf(" valid: %d, connected: \n", !!Valid());
  64. for( auto i : m_connected )
  65. {
  66. TRACK* t = static_cast<TRACK*>( i->Parent() );
  67. printf( " - %p %d\n", t, t->Type() );
  68. }
  69. }
  70. int CN_ZONE::AnchorCount() const
  71. {
  72. if( !Valid() )
  73. return 0;
  74. const auto zone = static_cast<const ZONE_CONTAINER*>( Parent() );
  75. const auto& outline = zone->GetFilledPolysList().COutline( m_subpolyIndex );
  76. return outline.PointCount() ? 1 : 0;
  77. }
  78. const VECTOR2I CN_ZONE::GetAnchor( int n ) const
  79. {
  80. if( !Valid() )
  81. return VECTOR2I();
  82. const auto zone = static_cast<const ZONE_CONTAINER*> ( Parent() );
  83. const auto& outline = zone->GetFilledPolysList().COutline( m_subpolyIndex );
  84. return outline.CPoint( 0 );
  85. }
  86. void CN_ITEM::RemoveInvalidRefs()
  87. {
  88. for( auto it = m_connected.begin(); it != m_connected.end(); )
  89. {
  90. if( !(*it)->Valid() )
  91. it = m_connected.erase( it );
  92. else
  93. ++it;
  94. }
  95. }
  96. CN_ITEM* CN_LIST::Add( D_PAD* pad )
  97. {
  98. auto item = new CN_ITEM( pad, false, 1 );
  99. item->AddAnchor( pad->ShapePos() );
  100. item->SetLayers( LAYER_RANGE( F_Cu, B_Cu ) );
  101. switch( pad->GetAttribute() )
  102. {
  103. case PAD_ATTRIB_SMD:
  104. case PAD_ATTRIB_HOLE_NOT_PLATED:
  105. case PAD_ATTRIB_CONN:
  106. {
  107. LSET lmsk = pad->GetLayerSet();
  108. for( int i = 0; i <= MAX_CU_LAYERS; i++ )
  109. {
  110. if( lmsk[i] )
  111. {
  112. item->SetLayer( i );
  113. break;
  114. }
  115. }
  116. break;
  117. }
  118. default:
  119. break;
  120. }
  121. addItemtoTree( item );
  122. m_items.push_back( item );
  123. SetDirty();
  124. return item;
  125. }
  126. CN_ITEM* CN_LIST::Add( TRACK* track )
  127. {
  128. auto item = new CN_ITEM( track, true );
  129. m_items.push_back( item );
  130. item->AddAnchor( track->GetStart() );
  131. item->AddAnchor( track->GetEnd() );
  132. item->SetLayer( track->GetLayer() );
  133. addItemtoTree( item );
  134. SetDirty();
  135. return item;
  136. }
  137. CN_ITEM* CN_LIST::Add( VIA* via )
  138. {
  139. auto item = new CN_ITEM( via, true, 1 );
  140. m_items.push_back( item );
  141. item->AddAnchor( via->GetStart() );
  142. item->SetLayers( LAYER_RANGE( F_Cu, B_Cu ) );
  143. addItemtoTree( item );
  144. SetDirty();
  145. return item;
  146. }
  147. const std::vector<CN_ITEM*> CN_LIST::Add( ZONE_CONTAINER* zone )
  148. {
  149. const auto& polys = zone->GetFilledPolysList();
  150. std::vector<CN_ITEM*> rv;
  151. for( int j = 0; j < polys.OutlineCount(); j++ )
  152. {
  153. CN_ZONE* zitem = new CN_ZONE( zone, false, j );
  154. const auto& outline = zone->GetFilledPolysList().COutline( j );
  155. for( int k = 0; k < outline.PointCount(); k++ )
  156. zitem->AddAnchor( outline.CPoint( k ) );
  157. m_items.push_back( zitem );
  158. zitem->SetLayer( zone->GetLayer() );
  159. addItemtoTree( zitem );
  160. rv.push_back( zitem );
  161. SetDirty();
  162. }
  163. return rv;
  164. }
  165. void CN_LIST::RemoveInvalidItems( std::vector<CN_ITEM*>& aGarbage )
  166. {
  167. if( !m_hasInvalid )
  168. return;
  169. auto lastItem = std::remove_if(m_items.begin(), m_items.end(), [&aGarbage] ( CN_ITEM* item )
  170. {
  171. if( !item->Valid() )
  172. {
  173. aGarbage.push_back ( item );
  174. return true;
  175. }
  176. return false;
  177. } );
  178. m_items.resize( lastItem - m_items.begin() );
  179. for( auto item : m_items )
  180. item->RemoveInvalidRefs();
  181. for( auto item : aGarbage )
  182. m_index.Remove( item );
  183. m_hasInvalid = false;
  184. }
  185. BOARD_CONNECTED_ITEM* CN_ANCHOR::Parent() const
  186. {
  187. assert( m_item->Valid() );
  188. return m_item->Parent();
  189. }
  190. bool CN_ANCHOR::Valid() const
  191. {
  192. if( !m_item )
  193. return false;
  194. return m_item->Valid();
  195. }
  196. bool CN_ANCHOR::IsDangling() const
  197. {
  198. if( !m_cluster )
  199. return true;
  200. // the minimal number of items connected to item_ref
  201. // at this anchor point to decide the anchor is *not* dangling
  202. size_t minimal_count = 1;
  203. size_t connected_count = m_item->ConnectedItems().size();
  204. // a via can be removed if connected to only one other item.
  205. if( Parent()->Type() == PCB_VIA_T )
  206. return connected_count < 2;
  207. if( m_item->AnchorCount() == 1 )
  208. return connected_count < minimal_count;
  209. // Only items with multiple anchors might have additional items connected that we
  210. // should ignore for this calculation.
  211. for( auto item : m_item->ConnectedItems() )
  212. {
  213. if( !item->Parent()->HitTest( wxPoint( Pos().x, Pos().y ) ) )
  214. connected_count--;
  215. }
  216. return connected_count < minimal_count;
  217. }
  218. CN_CLUSTER::CN_CLUSTER()
  219. {
  220. m_items.reserve( 64 );
  221. m_originPad = nullptr;
  222. m_originNet = -1;
  223. m_conflicting = false;
  224. }
  225. CN_CLUSTER::~CN_CLUSTER()
  226. {
  227. }
  228. wxString CN_CLUSTER::OriginNetName() const
  229. {
  230. if( !m_originPad || !m_originPad->Valid() )
  231. return "<none>";
  232. else
  233. return m_originPad->Parent()->GetNetname();
  234. }
  235. bool CN_CLUSTER::Contains( const CN_ITEM* aItem )
  236. {
  237. return std::find( m_items.begin(), m_items.end(), aItem ) != m_items.end();
  238. }
  239. bool CN_CLUSTER::Contains( const BOARD_CONNECTED_ITEM* aItem )
  240. {
  241. return std::find_if( m_items.begin(), m_items.end(), [ &aItem ] ( const CN_ITEM* item )
  242. { return item->Valid() && item->Parent() == aItem; } ) != m_items.end();
  243. }
  244. void CN_CLUSTER::Dump()
  245. {
  246. for( auto item : m_items )
  247. {
  248. wxLogTrace( "CN", " - item : %p bitem : %p type : %d inet %s\n", item, item->Parent(),
  249. item->Parent()->Type(), (const char*) item->Parent()->GetNetname().c_str() );
  250. printf( "- item : %p bitem : %p type : %d inet %s\n", item, item->Parent(),
  251. item->Parent()->Type(), (const char*) item->Parent()->GetNetname().c_str() );
  252. item->Dump();
  253. }
  254. }
  255. void CN_CLUSTER::Add( CN_ITEM* item )
  256. {
  257. m_items.push_back( item );
  258. if( m_originNet < 0 )
  259. {
  260. m_originNet = item->Net();
  261. }
  262. if( item->Parent()->Type() == PCB_PAD_T )
  263. {
  264. if( !m_originPad )
  265. {
  266. m_originPad = item;
  267. m_originNet = item->Net();
  268. }
  269. if( m_originPad && item->Net() != m_originNet )
  270. {
  271. m_conflicting = true;
  272. }
  273. }
  274. }