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.

368 lines
12 KiB

  1. /*
  2. * KiRouter - a push-and-(sometimes-)shove PCB router
  3. *
  4. * Copyright (C) 2013-2014 CERN
  5. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  6. * Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
  7. *
  8. * This program is free software: you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by the
  10. * Free Software Foundation, either version 3 of the License, or (at your
  11. * option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #include "pns_node.h"
  22. #include "pns_item.h"
  23. #include "pns_line.h"
  24. #include "pns_router.h"
  25. #include <geometry/shape_compound.h>
  26. #include <geometry/shape_poly_set.h>
  27. typedef VECTOR2I::extended_type ecoord;
  28. namespace PNS {
  29. static void dumpObstacles( const PNS::NODE::OBSTACLES &obstacles )
  30. {
  31. printf( "&&&& %zu obstacles: \n", obstacles.size() );
  32. for( const auto& obs : obstacles )
  33. {
  34. printf( "%p [%s] - %p [%s], clearance %d\n",
  35. obs.m_head, obs.m_head->KindStr().c_str(),
  36. obs.m_item, obs.m_item->KindStr().c_str(),
  37. obs.m_clearance );
  38. }
  39. }
  40. // prune self-collisions, i.e. a via/pad annular ring with its own hole
  41. static bool shouldWeConsiderHoleCollisions( const ITEM* aItem, const ITEM* aHead )
  42. {
  43. const HOLE* holeI = aItem->OfKind( ITEM::HOLE_T ) ? static_cast<const HOLE*>( aItem ) : nullptr;
  44. const HOLE* holeH = aHead->OfKind( ITEM::HOLE_T ) ? static_cast<const HOLE*>( aHead ) : nullptr;
  45. if( holeI && holeH ) // hole-to-hole case
  46. {
  47. const ITEM* parentI = holeI->ParentPadVia();
  48. const ITEM* parentH = holeH->ParentPadVia();
  49. if( !parentH || !parentI )
  50. return true;
  51. const VIA* parentViaI = dyn_cast<const VIA*>( parentI );
  52. const VIA* parentViaH = dyn_cast<const VIA*>( parentH );
  53. // Note to self: the if() below is an ugly heuristic to determine if we aren't trying
  54. // to check for collisions of the hole of the via with another (although identical)
  55. // copy of it. Such case occurs when checking a LINE against a NODE where this LINE
  56. // has been already added. LINE has no notion of ownership of it's via (it's just a
  57. // copy) and before hole-to-hole clearance support has been introduced it didn't matter
  58. // becasue we didn't consider collisions of the objects belonging to the same net anyway
  59. // Now that hole clearance check doesn't care about the nets assigned to the parent
  60. // vias/solids, I'll probably have to refactor the LINE class to manage ownership of
  61. // its (optional) VIA. For the moment, we just treat via holes that are geometrically
  62. // identical and belonging to the same net as non-colliding.
  63. if( parentViaI && parentViaH && parentViaI->Pos() == parentViaH->Pos()
  64. && parentViaI->PadstackMatches( *parentViaH )
  65. && parentViaI->Net() == parentViaH->Net()
  66. && parentViaI->Drill() == parentViaH->Drill() )
  67. return false;
  68. return parentI != parentH;
  69. }
  70. if( holeI )
  71. return holeI->ParentPadVia() != aHead;
  72. else if( holeH )
  73. return holeH->ParentPadVia() != aItem;
  74. else
  75. return true;
  76. }
  77. std::set<int> ITEM::RelevantShapeLayers( const ITEM* aOther ) const
  78. {
  79. std::vector<int> myLayers = UniqueShapeLayers();
  80. std::vector<int> otherLayers = aOther->UniqueShapeLayers();
  81. if( !HasUniqueShapeLayers() && !aOther->HasUniqueShapeLayers() )
  82. return { -1 };
  83. // TODO(JE) at this point we should also mask off the layers of each item.
  84. // In the case that one item is a via and the other is a track, we don't want to test
  85. // more than once even if the via has multiple unique layers
  86. std::set<int> relevantLayers;
  87. std::set_union( myLayers.begin(), myLayers.end(), otherLayers.begin(), otherLayers.end(),
  88. std::inserter( relevantLayers, relevantLayers.begin() ) );
  89. return relevantLayers;
  90. }
  91. bool ITEM::collideSimple( const ITEM* aHead, const NODE* aNode, int aLayer,
  92. COLLISION_SEARCH_CONTEXT* aCtx ) const
  93. {
  94. // Note: if 'this' is a pad or a via then its hole is a separate PNS::ITEM in the node's
  95. // index and we don't need to deal with holeI here. The same is *not* true of the routing
  96. // "head", so we do need to handle holeH.
  97. int lineWidthI = 0;
  98. //const SHAPE* shapeH = aHead->Shape();
  99. const HOLE* holeH = aHead->Hole();
  100. const HOLE* holeI = Hole();
  101. int lineWidthH = 0;
  102. bool collisionsFound = false;
  103. if( this == aHead ) // we cannot be self-colliding
  104. return false;
  105. if ( !shouldWeConsiderHoleCollisions( this, aHead ) )
  106. return false;
  107. // Special cases for "head" lines with vias attached at the end. Note that this does not
  108. // support head-line-via to head-line-via collisions, but you can't route two independent
  109. // tracks at once so it shouldn't come up.
  110. if( const auto line = dyn_cast<const LINE*>( this ) )
  111. {
  112. if( line->EndsWithVia() )
  113. collisionsFound |= line->Via().collideSimple( aHead, aNode, aLayer, aCtx );
  114. }
  115. if( const auto line = dyn_cast<const LINE*>( aHead ) )
  116. {
  117. if( line->EndsWithVia() )
  118. collisionsFound |= line->Via().collideSimple( this, aNode, aLayer, aCtx );
  119. }
  120. // And a special case for the "head" via's hole.
  121. if( aHead->HasHole() && shouldWeConsiderHoleCollisions( this, holeH ) )
  122. {
  123. // Skip net check when doing hole-to-hole collisions.
  124. if( Kind() == HOLE_T || Net() != holeH->Net() )
  125. collisionsFound |= collideSimple( holeH, aNode, aLayer, aCtx );
  126. }
  127. if( HasHole() && shouldWeConsiderHoleCollisions( holeI, aHead ) )
  128. {
  129. collisionsFound |= holeI->collideSimple( aHead, aNode, aLayer, aCtx );
  130. }
  131. // Sadly collision routines ignore SHAPE_POLY_LINE widths so we have to pass them in as part
  132. // of the clearance value.
  133. if( m_kind == LINE_T )
  134. lineWidthI = static_cast<const LINE*>( this )->Width() / 2;
  135. if( aHead->m_kind == LINE_T )
  136. lineWidthH = static_cast<const LINE*>( aHead )->Width() / 2;
  137. // check if we are not on completely different layers first
  138. if( !m_layers.Overlaps( aHead->m_layers ) )
  139. return false;
  140. // fixme: this f***ing singleton must go...
  141. ROUTER* router = ROUTER::GetInstance();
  142. ROUTER_IFACE* iface = router ? router->GetInterface() : nullptr;
  143. bool differentNetsOnly = true;
  144. bool enforce = false;
  145. int clearance;
  146. if( aCtx )
  147. differentNetsOnly = aCtx->options.m_differentNetsOnly;
  148. // Hole-to-hole collisions don't have anything to do with nets
  149. if( Kind() == HOLE_T && aHead->Kind() == HOLE_T )
  150. differentNetsOnly = false;
  151. if( differentNetsOnly && Net() == aHead->Net() && aHead->Net() )
  152. {
  153. // same nets? no clearance!
  154. clearance = -1;
  155. }
  156. else if( differentNetsOnly && ( IsFreePad() || aHead->IsFreePad() ) )
  157. {
  158. // a pad associated with a "free" pin (NIC) doesn't have a net until it has been used
  159. clearance = -1;
  160. }
  161. else if( aNode->GetRuleResolver()->IsKeepout( this, aHead, &enforce )
  162. || aNode->GetRuleResolver()->IsKeepout( aHead, this, &enforce ) )
  163. {
  164. if( enforce )
  165. clearance = 0; // keepouts are exact boundary; no clearance
  166. else
  167. clearance = -1;
  168. }
  169. else if( iface && !iface->IsFlashedOnLayer( this, aHead->Layers() ) )
  170. {
  171. clearance = -1;
  172. }
  173. else if( iface && !iface->IsFlashedOnLayer( aHead, Layers() ) )
  174. {
  175. clearance = -1;
  176. }
  177. else if( aCtx && aCtx->options.m_overrideClearance >= 0 )
  178. {
  179. clearance = aCtx->options.m_overrideClearance;
  180. }
  181. else
  182. {
  183. clearance = aNode->GetClearance( this, aHead, aCtx ? aCtx->options.m_useClearanceEpsilon
  184. : false );
  185. }
  186. if( clearance >= 0 )
  187. {
  188. // Note: we can't do castellation or net-tie processing in GetClearance() because they
  189. // depend on *where* the collision is.
  190. bool checkCastellation = ( m_parent && m_parent->GetLayer() == Edge_Cuts )
  191. || aNode->GetRuleResolver()->IsNonPlatedSlot( this );
  192. bool checkNetTie = aNode->GetRuleResolver()->IsInNetTie( this );
  193. const SHAPE* shapeI = Shape( aLayer );
  194. const SHAPE* shapeH = aHead->Shape( aLayer );
  195. if( checkCastellation || checkNetTie )
  196. {
  197. // Slow method
  198. int actual;
  199. VECTOR2I pos;
  200. // The extra "1" here is to account for the fact that the hulls are built to exactly
  201. // the clearance distance, so we need to allow for no collision when exactly at the
  202. // clearance distance.
  203. if( shapeH->Collide( shapeI, clearance + lineWidthH + lineWidthI - 1, &actual, &pos ) )
  204. {
  205. if( checkCastellation && aNode->QueryEdgeExclusions( pos ) )
  206. return false;
  207. if( checkNetTie && aNode->GetRuleResolver()->IsNetTieExclusion( aHead, pos, this ) )
  208. return false;
  209. if( aCtx )
  210. {
  211. collisionsFound = true;
  212. OBSTACLE obs;
  213. obs.m_head = const_cast<ITEM*>( aHead );
  214. obs.m_item = const_cast<ITEM*>( this );
  215. obs.m_clearance = clearance;
  216. obs.m_distFirst = 0;
  217. obs.m_maxFanoutWidth = 0;
  218. aCtx->obstacles.insert( obs );
  219. }
  220. else
  221. {
  222. return true;
  223. }
  224. }
  225. }
  226. else
  227. {
  228. // Fast method
  229. // The extra "1" here is to account for the fact that the hulls are built to exactly
  230. // the clearance distance, so we need to allow for no collision when exactly at the
  231. // clearance distance.
  232. if( shapeH->Collide( shapeI, clearance + lineWidthH + lineWidthI - 1 ) )
  233. {
  234. if( aCtx )
  235. {
  236. collisionsFound = true;
  237. OBSTACLE obs;
  238. obs.m_head = const_cast<ITEM*>( aHead );
  239. obs.m_item = const_cast<ITEM*>( this );
  240. obs.m_clearance = clearance;
  241. obs.m_distFirst = 0;
  242. obs.m_maxFanoutWidth = 0;
  243. aCtx->obstacles.insert( obs );
  244. }
  245. else
  246. {
  247. return true;
  248. }
  249. }
  250. }
  251. }
  252. return collisionsFound;
  253. }
  254. bool ITEM::Collide( const ITEM* aOther, const NODE* aNode, int aLayer,
  255. COLLISION_SEARCH_CONTEXT *aCtx ) const
  256. {
  257. if( collideSimple( aOther, aNode, aLayer, aCtx ) )
  258. return true;
  259. return false;
  260. }
  261. std::string ITEM::KindStr() const
  262. {
  263. switch( m_kind )
  264. {
  265. case ARC_T: return "arc";
  266. case LINE_T: return "line";
  267. case SEGMENT_T: return "segment";
  268. case VIA_T: return "via";
  269. case JOINT_T: return "joint";
  270. case SOLID_T: return "solid";
  271. case DIFF_PAIR_T: return "diff-pair";
  272. case HOLE_T: return "hole";
  273. default: return "unknown";
  274. }
  275. }
  276. ITEM::~ITEM()
  277. {
  278. }
  279. const std::string ITEM::Format() const
  280. {
  281. ROUTER* router = ROUTER::GetInstance();
  282. ROUTER_IFACE* iface = router ? router->GetInterface() : nullptr;
  283. std::stringstream ss;
  284. ss << KindStr() << " ";
  285. if( iface )
  286. ss << "net " << iface->GetNetName( Net() ) << " ";
  287. ss << "layers " << m_layers.Start() << " " << m_layers.End();
  288. return ss.str();
  289. }
  290. const NODE* ITEM::OwningNode() const
  291. {
  292. if( ParentPadVia() )
  293. return static_cast<const NODE*>( ParentPadVia()->Owner() );
  294. else
  295. return static_cast<const NODE*>( Owner() );
  296. }
  297. LINKED_ITEM::UNIQ_ID LINKED_ITEM::genNextUid()
  298. {
  299. static UNIQ_ID uidCount = 0; // fixme: make atomic
  300. return uidCount++;
  301. }
  302. } // namespace PNS