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.

445 lines
11 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  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-2022 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 <core/kicad_algo.h>
  27. #include <macros.h>
  28. #include <connectivity/connectivity_items.h>
  29. #include <trigo.h>
  30. #include <wx/log.h>
  31. int CN_ITEM::AnchorCount() const
  32. {
  33. if( !m_valid )
  34. return 0;
  35. switch( m_parent->Type() )
  36. {
  37. case PCB_TRACE_T:
  38. case PCB_ARC_T:
  39. return 2; // start and end
  40. default:
  41. return 1;
  42. }
  43. }
  44. const VECTOR2I CN_ITEM::GetAnchor( int n ) const
  45. {
  46. if( !m_valid )
  47. return VECTOR2I();
  48. switch( m_parent->Type() )
  49. {
  50. case PCB_PAD_T:
  51. return static_cast<PAD*>( m_parent )->GetPosition();
  52. case PCB_TRACE_T:
  53. case PCB_ARC_T:
  54. if( n == 0 )
  55. return static_cast<const PCB_TRACK*>( m_parent )->GetStart();
  56. else
  57. return static_cast<const PCB_TRACK*>( m_parent )->GetEnd();
  58. case PCB_VIA_T:
  59. return static_cast<const PCB_VIA*>( m_parent )->GetStart();
  60. default:
  61. UNIMPLEMENTED_FOR( m_parent->GetClass() );
  62. return VECTOR2I();
  63. }
  64. }
  65. void CN_ITEM::Dump()
  66. {
  67. wxLogDebug(" valid: %d, connected: \n", !!Valid());
  68. for( CN_ITEM* i : m_connected )
  69. {
  70. PCB_TRACK* t = static_cast<PCB_TRACK*>( i->Parent() );
  71. wxLogDebug( wxT( " - %p %d\n" ), t, t->Type() );
  72. }
  73. }
  74. int CN_ZONE_LAYER::AnchorCount() const
  75. {
  76. if( !Valid() )
  77. return 0;
  78. const ZONE* zone = static_cast<const ZONE*>( Parent() );
  79. return zone->GetFilledPolysList( m_layer )->COutline( m_subpolyIndex ).PointCount() ? 1 : 0;
  80. }
  81. const VECTOR2I CN_ZONE_LAYER::GetAnchor( int n ) const
  82. {
  83. if( !Valid() )
  84. return VECTOR2I();
  85. const ZONE* zone = static_cast<const ZONE*>( Parent() );
  86. return zone->GetFilledPolysList( m_layer )->COutline( m_subpolyIndex ).CPoint( 0 );
  87. }
  88. void CN_ITEM::RemoveInvalidRefs()
  89. {
  90. for( auto it = m_connected.begin(); it != m_connected.end(); /* increment in loop */ )
  91. {
  92. if( !(*it)->Valid() )
  93. it = m_connected.erase( it );
  94. else
  95. ++it;
  96. }
  97. }
  98. CN_ITEM* CN_LIST::Add( PAD* pad )
  99. {
  100. if( !pad->IsOnCopperLayer() )
  101. return nullptr;
  102. auto item = new CN_ITEM( pad, false, 1 );
  103. item->AddAnchor( pad->ShapePos() );
  104. item->SetLayers( LAYER_RANGE( F_Cu, B_Cu ) );
  105. switch( pad->GetAttribute() )
  106. {
  107. case PAD_ATTRIB::SMD:
  108. case PAD_ATTRIB::NPTH:
  109. case PAD_ATTRIB::CONN:
  110. {
  111. LSET lmsk = pad->GetLayerSet();
  112. for( int i = 0; i <= MAX_CU_LAYERS; i++ )
  113. {
  114. if( lmsk[i] )
  115. {
  116. item->SetLayer( i );
  117. break;
  118. }
  119. }
  120. break;
  121. }
  122. default:
  123. break;
  124. }
  125. addItemtoTree( item );
  126. m_items.push_back( item );
  127. SetDirty();
  128. return item;
  129. }
  130. CN_ITEM* CN_LIST::Add( PCB_TRACK* track )
  131. {
  132. CN_ITEM* item = new CN_ITEM( track, true );
  133. m_items.push_back( item );
  134. item->AddAnchor( track->GetStart() );
  135. item->AddAnchor( track->GetEnd() );
  136. item->SetLayer( track->GetLayer() );
  137. addItemtoTree( item );
  138. SetDirty();
  139. return item;
  140. }
  141. CN_ITEM* CN_LIST::Add( PCB_ARC* aArc )
  142. {
  143. CN_ITEM* item = new CN_ITEM( aArc, true );
  144. m_items.push_back( item );
  145. item->AddAnchor( aArc->GetStart() );
  146. item->AddAnchor( aArc->GetEnd() );
  147. item->SetLayer( aArc->GetLayer() );
  148. addItemtoTree( item );
  149. SetDirty();
  150. return item;
  151. }
  152. CN_ITEM* CN_LIST::Add( PCB_VIA* via )
  153. {
  154. CN_ITEM* item = new CN_ITEM( via, !via->GetIsFree(), 1 );
  155. m_items.push_back( item );
  156. item->AddAnchor( via->GetStart() );
  157. item->SetLayers( LAYER_RANGE( via->TopLayer(), via->BottomLayer() ) );
  158. addItemtoTree( item );
  159. SetDirty();
  160. return item;
  161. }
  162. const std::vector<CN_ITEM*> CN_LIST::Add( ZONE* zone, PCB_LAYER_ID aLayer )
  163. {
  164. const std::shared_ptr<SHAPE_POLY_SET>& polys = zone->GetFilledPolysList( aLayer );
  165. std::vector<CN_ITEM*> rv;
  166. for( int j = 0; j < polys->OutlineCount(); j++ )
  167. {
  168. CN_ZONE_LAYER* zitem = new CN_ZONE_LAYER( zone, aLayer, j );
  169. zitem->BuildRTree();
  170. for( VECTOR2I pt : zone->GetFilledPolysList( aLayer )->COutline( j ).CPoints() )
  171. zitem->AddAnchor( pt );
  172. rv.push_back( Add( zitem ) );
  173. }
  174. return rv;
  175. }
  176. CN_ITEM* CN_LIST::Add( CN_ZONE_LAYER* zitem )
  177. {
  178. m_items.push_back( zitem );
  179. addItemtoTree( zitem );
  180. SetDirty();
  181. return zitem;
  182. }
  183. void CN_LIST::RemoveInvalidItems( std::vector<CN_ITEM*>& aGarbage )
  184. {
  185. if( !m_hasInvalid )
  186. return;
  187. auto lastItem = std::remove_if( m_items.begin(), m_items.end(),
  188. [&aGarbage]( CN_ITEM* item )
  189. {
  190. if( !item->Valid() )
  191. {
  192. aGarbage.push_back ( item );
  193. return true;
  194. }
  195. return false;
  196. } );
  197. m_items.resize( lastItem - m_items.begin() );
  198. for( CN_ITEM* item : m_items )
  199. item->RemoveInvalidRefs();
  200. for( CN_ITEM* item : aGarbage )
  201. m_index.Remove( item );
  202. m_hasInvalid = false;
  203. }
  204. BOARD_CONNECTED_ITEM* CN_ANCHOR::Parent() const
  205. {
  206. assert( m_item->Valid() );
  207. return m_item->Parent();
  208. }
  209. bool CN_ANCHOR::Valid() const
  210. {
  211. if( !m_item )
  212. return false;
  213. return m_item->Valid();
  214. }
  215. bool CN_ANCHOR::IsDangling() const
  216. {
  217. int accuracy = 0;
  218. if( !m_cluster )
  219. return true;
  220. // the minimal number of items connected to item_ref
  221. // at this anchor point to decide the anchor is *not* dangling
  222. size_t minimal_count = 1;
  223. size_t connected_count = m_item->ConnectedItems().size();
  224. // a via can be removed if connected to only one other item.
  225. if( Parent()->Type() == PCB_VIA_T )
  226. return connected_count < 2;
  227. if( m_item->AnchorCount() == 1 )
  228. return connected_count < minimal_count;
  229. if( Parent()->Type() == PCB_TRACE_T || Parent()->Type() == PCB_ARC_T )
  230. accuracy = KiROUND( static_cast<const PCB_TRACK*>( Parent() )->GetWidth() / 2 );
  231. // Items with multiple anchors have usually items connected to each anchor.
  232. // We want only the item count of this anchor point
  233. connected_count = 0;
  234. for( CN_ITEM* item : m_item->ConnectedItems() )
  235. {
  236. if( item->Parent()->Type() == PCB_ZONE_T )
  237. {
  238. ZONE* zone = static_cast<ZONE*>( item->Parent() );
  239. if( zone->HitTestFilledArea( ToLAYER_ID( item->Layer() ), Pos(), accuracy ) )
  240. connected_count++;
  241. }
  242. else if( item->Parent()->HitTest( Pos(), accuracy ) )
  243. {
  244. connected_count++;
  245. }
  246. }
  247. return connected_count < minimal_count;
  248. }
  249. int CN_ANCHOR::ConnectedItemsCount() const
  250. {
  251. if( !m_cluster )
  252. return 0;
  253. int connected_count = 0;
  254. for( CN_ITEM* item : m_item->ConnectedItems() )
  255. {
  256. if( item->Parent()->Type() == PCB_ZONE_T )
  257. {
  258. ZONE* zone = static_cast<ZONE*>( item->Parent() );
  259. if( zone->HitTestFilledArea( ToLAYER_ID( item->Layer() ), Pos() ) )
  260. connected_count++;
  261. }
  262. else if( item->Parent()->HitTest( Pos() ) )
  263. {
  264. connected_count++;
  265. }
  266. }
  267. return connected_count;
  268. }
  269. CN_CLUSTER::CN_CLUSTER()
  270. {
  271. m_items.reserve( 64 );
  272. m_originPad = nullptr;
  273. m_originNet = -1;
  274. m_conflicting = false;
  275. }
  276. CN_CLUSTER::~CN_CLUSTER()
  277. {
  278. }
  279. wxString CN_CLUSTER::OriginNetName() const
  280. {
  281. if( !m_originPad || !m_originPad->Valid() )
  282. return "<none>";
  283. else
  284. return m_originPad->Parent()->GetNetname();
  285. }
  286. bool CN_CLUSTER::Contains( const CN_ITEM* aItem )
  287. {
  288. return alg::contains( m_items, aItem );
  289. }
  290. bool CN_CLUSTER::Contains( const BOARD_CONNECTED_ITEM* aItem )
  291. {
  292. return std::find_if( m_items.begin(), m_items.end(),
  293. [&aItem]( const CN_ITEM* item )
  294. {
  295. return item->Valid() && item->Parent() == aItem;
  296. } ) != m_items.end();
  297. }
  298. void CN_CLUSTER::Dump()
  299. {
  300. for( auto item : m_items )
  301. {
  302. wxLogTrace( wxT( "CN" ), wxT( " - item : %p bitem : %p type : %d inet %s\n" ),
  303. item,
  304. item->Parent(),
  305. item->Parent()->Type(),
  306. (const char*) item->Parent()->GetNetname().c_str() );
  307. wxLogTrace( wxT( "CN" ), wxT( "- item : %p bitem : %p type : %d inet %s\n" ),
  308. item,
  309. item->Parent(),
  310. item->Parent()->Type(),
  311. (const char*) item->Parent()->GetNetname().c_str() );
  312. item->Dump();
  313. }
  314. }
  315. void CN_CLUSTER::Add( CN_ITEM* item )
  316. {
  317. m_items.push_back( item );
  318. int netCode = item->Net();
  319. if( netCode <= 0 )
  320. return;
  321. if( m_originNet <= 0 )
  322. m_originNet = netCode;
  323. if( item->Parent()->Type() == PCB_PAD_T )
  324. {
  325. if( m_netRanks.count( netCode ) )
  326. {
  327. m_netRanks[netCode]++;
  328. if( m_netRanks.count( m_originNet ) && m_netRanks[netCode] > m_netRanks[m_originNet] )
  329. {
  330. m_originPad = item;
  331. m_originNet = netCode;
  332. }
  333. }
  334. else
  335. {
  336. m_netRanks[netCode] = 1;
  337. if( !m_originPad )
  338. {
  339. m_originPad = item;
  340. m_originNet = netCode;
  341. }
  342. }
  343. if( m_originPad && item->Net() != m_originNet )
  344. m_conflicting = true;
  345. }
  346. }