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.

274 lines
7.1 KiB

5 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2004-2022 KiCad Developers.
  5. *
  6. * This program is free software: you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation, either version 3 of the License, or (at your
  9. * option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <cstdio>
  20. #include <memory>
  21. #include <reporter.h>
  22. #include <board.h>
  23. #include <string_utils.h>
  24. #include <pcbexpr_evaluator.h>
  25. #include <connectivity/connectivity_data.h>
  26. #include <connectivity/connectivity_algo.h>
  27. #include <connectivity/from_to_cache.h>
  28. void FROM_TO_CACHE::buildEndpointList( )
  29. {
  30. m_ftEndpoints.clear();
  31. for( FOOTPRINT* footprint : m_board->Footprints() )
  32. {
  33. for( PAD* pad : footprint->Pads() )
  34. {
  35. FT_ENDPOINT ent;
  36. ent.name = footprint->GetReference() + wxT( "-" ) + pad->GetNumber();
  37. ent.parent = pad;
  38. m_ftEndpoints.push_back( ent );
  39. ent.name = footprint->GetReference();
  40. ent.parent = pad;
  41. m_ftEndpoints.push_back( ent );
  42. }
  43. }
  44. }
  45. enum PATH_STATUS {
  46. PS_OK = 0,
  47. PS_MULTIPLE_PATHS = -1,
  48. PS_NO_PATH = -2
  49. };
  50. static bool isVertexVisited( CN_ITEM* v, const std::vector<CN_ITEM*>& path )
  51. {
  52. for( CN_ITEM* u : path )
  53. {
  54. if ( u == v )
  55. return true;
  56. }
  57. return false;
  58. }
  59. static PATH_STATUS uniquePathBetweenNodes( CN_ITEM* u, CN_ITEM* v, std::vector<CN_ITEM*>& outPath )
  60. {
  61. using Path = std::vector<CN_ITEM*>;
  62. std::deque<Path> Q;
  63. Path pInit;
  64. bool pathFound = false;
  65. pInit.push_back( u );
  66. Q.push_back( pInit );
  67. while( Q.size() )
  68. {
  69. Path path = Q.front();
  70. Q.pop_front();
  71. CN_ITEM* last = path.back();
  72. if( last == v )
  73. {
  74. outPath = path;
  75. if( pathFound )
  76. return PS_MULTIPLE_PATHS;
  77. pathFound = true;
  78. }
  79. for( CN_ITEM* ci : last->ConnectedItems() )
  80. {
  81. bool vertexVisited = isVertexVisited( ci, path );
  82. for( std::vector<CN_ITEM*>& p : Q )
  83. if( isVertexVisited( ci, p ) )
  84. {
  85. vertexVisited = true;
  86. break;
  87. }
  88. if( !vertexVisited )
  89. {
  90. Path newpath( path );
  91. newpath.push_back( ci );
  92. Q.push_back( newpath );
  93. }
  94. }
  95. }
  96. return pathFound ? PS_OK : PS_NO_PATH;
  97. };
  98. int FROM_TO_CACHE::cacheFromToPaths( const wxString& aFrom, const wxString& aTo )
  99. {
  100. std::vector<FT_PATH> paths;
  101. std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
  102. std::shared_ptr<CN_CONNECTIVITY_ALGO> cnAlgo = connectivity->GetConnectivityAlgo();
  103. for( FT_ENDPOINT& endpoint : m_ftEndpoints )
  104. {
  105. if( WildCompareString( aFrom, endpoint.name, false ) )
  106. {
  107. FT_PATH p;
  108. p.net = endpoint.parent->GetNetCode();
  109. p.from = endpoint.parent;
  110. p.to = nullptr;
  111. paths.push_back(p);
  112. }
  113. }
  114. for( FT_PATH& path : paths )
  115. {
  116. int count = 0;
  117. wxString fromName = path.from->GetParentFootprint()->GetReference()
  118. + wxT( "-" ) + path.from->GetNumber();
  119. auto padCandidates = connectivity->GetConnectedItems( path.from,
  120. { PCB_PAD_T, PCB_ARC_T, PCB_VIA_T,
  121. PCB_TRACE_T } );
  122. PAD* toPad = nullptr;
  123. for( BOARD_CONNECTED_ITEM* pitem : padCandidates )
  124. {
  125. if( pitem == path.from )
  126. continue;
  127. if( pitem->Type() != PCB_PAD_T )
  128. continue;
  129. const PAD *pad = static_cast<const PAD*>( pitem );
  130. wxString toName = pad->GetParentFootprint()->GetReference()
  131. + wxT( "-" ) + pad->GetNumber();
  132. for( const FT_ENDPOINT& endpoint : m_ftEndpoints )
  133. {
  134. if( pad == endpoint.parent )
  135. {
  136. if( WildCompareString( aTo, endpoint.name, false ) )
  137. {
  138. count++;
  139. toPad = endpoint.parent;
  140. path.to = toPad;
  141. path.fromName = fromName;
  142. path.toName = toName;
  143. path.fromWildcard = aFrom;
  144. path.toWildcard = aTo;
  145. if( count >= 2 )
  146. {
  147. // fixme: report this somewhere?
  148. path.to = nullptr;
  149. }
  150. }
  151. }
  152. }
  153. }
  154. }
  155. int newPaths = 0;
  156. for( FT_PATH& path : paths )
  157. {
  158. if( !path.from || !path.to )
  159. continue;
  160. CN_ITEM* cnFrom = cnAlgo->ItemEntry( path.from ).GetItems().front();
  161. CN_ITEM* cnTo = cnAlgo->ItemEntry( path.to ).GetItems().front();
  162. std::vector<CN_ITEM*> upath;
  163. auto result = uniquePathBetweenNodes( cnFrom, cnTo, upath );
  164. if( result == PS_OK )
  165. path.isUnique = true;
  166. else
  167. path.isUnique = false;
  168. if( result == PS_NO_PATH )
  169. continue;
  170. for( const auto item : upath )
  171. {
  172. path.pathItems.insert( item->Parent() );
  173. }
  174. m_ftPaths.push_back(path);
  175. newPaths++;
  176. }
  177. // reportAux( _("Cached %d paths\n"), newPaths );
  178. return newPaths;
  179. }
  180. bool FROM_TO_CACHE::IsOnFromToPath( BOARD_CONNECTED_ITEM* aItem, const wxString& aFrom, const wxString& aTo )
  181. {
  182. int nFromTosFound = 0;
  183. if( !m_board )
  184. return false;
  185. for( int attempt = 0; attempt < 2; attempt++ )
  186. {
  187. // item already belongs to path
  188. for( FT_PATH& ftPath : m_ftPaths )
  189. {
  190. if( aFrom == ftPath.fromWildcard && aTo == ftPath.toWildcard )
  191. {
  192. nFromTosFound++;
  193. if( ftPath.pathItems.count( aItem ) )
  194. return true;
  195. }
  196. }
  197. if( !nFromTosFound )
  198. cacheFromToPaths( aFrom, aTo );
  199. else
  200. return false;
  201. }
  202. return false;
  203. }
  204. void FROM_TO_CACHE::Rebuild( BOARD* aBoard )
  205. {
  206. m_board = aBoard;
  207. buildEndpointList();
  208. m_ftPaths.clear();
  209. }
  210. FROM_TO_CACHE::FT_PATH* FROM_TO_CACHE::QueryFromToPath( const std::set<BOARD_CONNECTED_ITEM*>& aItems )
  211. {
  212. for( FT_PATH& ftPath : m_ftPaths )
  213. {
  214. if ( ftPath.pathItems == aItems )
  215. return &ftPath;
  216. }
  217. return nullptr;
  218. }