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.

1041 lines
28 KiB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. /*
  2. * KiRouter - a push-and-(sometimes-)shove PCB router
  3. *
  4. * Copyright (C) 2013-2016 CERN
  5. * Copyright (C) 2016 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 <class_undoredo_container.h>
  22. #include <class_board.h>
  23. #include <class_board_connected_item.h>
  24. #include <class_module.h>
  25. #include <class_track.h>
  26. #include <board_commit.h>
  27. #include <layers_id_colors_and_visibility.h>
  28. #include <geometry/convex_hull.h>
  29. #include <wxPcbStruct.h>
  30. #include <unordered_set>
  31. #include <unordered_map>
  32. #include <view/view.h>
  33. #include <view/view_item.h>
  34. #include <view/view_group.h>
  35. #include <gal/graphics_abstraction_layer.h>
  36. #include <pcb_painter.h>
  37. #include <geometry/shape.h>
  38. #include <geometry/shape_line_chain.h>
  39. #include <geometry/shape_rect.h>
  40. #include <geometry/shape_circle.h>
  41. #include <geometry/shape_convex.h>
  42. #include <geometry/convex_hull.h>
  43. #include "pns_kicad_iface.h"
  44. #include "pns_routing_settings.h"
  45. #include "pns_sizes_settings.h"
  46. #include "pns_item.h"
  47. #include "pns_solid.h"
  48. #include "pns_segment.h"
  49. #include "pns_solid.h"
  50. #include "pns_itemset.h"
  51. #include "pns_node.h"
  52. #include "pns_topology.h"
  53. #include "pns_router.h"
  54. #include "pns_debug_decorator.h"
  55. #include "router_preview_item.h"
  56. class PNS_PCBNEW_RULE_RESOLVER : public PNS::RULE_RESOLVER
  57. {
  58. public:
  59. PNS_PCBNEW_RULE_RESOLVER( BOARD* aBoard, PNS::ROUTER* aRouter );
  60. virtual ~PNS_PCBNEW_RULE_RESOLVER();
  61. virtual int Clearance( const PNS::ITEM* aA, const PNS::ITEM* aB ) const override;
  62. virtual int Clearance( int aNetCode ) const override;
  63. virtual void OverrideClearance( bool aEnable, int aNetA = 0, int aNetB = 0, int aClearance = 0 ) override;
  64. virtual void UseDpGap( bool aUseDpGap ) override { m_useDpGap = aUseDpGap; }
  65. virtual int DpCoupledNet( int aNet ) override;
  66. virtual int DpNetPolarity( int aNet ) override;
  67. virtual bool DpNetPair( PNS::ITEM* aItem, int& aNetP, int& aNetN ) override;
  68. private:
  69. struct CLEARANCE_ENT
  70. {
  71. int coupledNet;
  72. int clearance;
  73. };
  74. int localPadClearance( const PNS::ITEM* aItem ) const;
  75. int matchDpSuffix( wxString aNetName, wxString& aComplementNet, wxString& aBaseDpName );
  76. PNS::ROUTER* m_router;
  77. BOARD* m_board;
  78. std::vector<CLEARANCE_ENT> m_netClearanceCache;
  79. std::unordered_map<const D_PAD*, int> m_localClearanceCache;
  80. int m_defaultClearance;
  81. bool m_overrideEnabled;
  82. int m_overrideNetA, m_overrideNetB;
  83. int m_overrideClearance;
  84. bool m_useDpGap;
  85. };
  86. PNS_PCBNEW_RULE_RESOLVER::PNS_PCBNEW_RULE_RESOLVER( BOARD* aBoard, PNS::ROUTER* aRouter ) :
  87. m_router( aRouter ),
  88. m_board( aBoard )
  89. {
  90. PNS::NODE* world = m_router->GetWorld();
  91. PNS::TOPOLOGY topo( world );
  92. m_netClearanceCache.resize( m_board->GetNetCount() );
  93. // Build clearance cache for net classes
  94. for( unsigned int i = 0; i < m_board->GetNetCount(); i++ )
  95. {
  96. NETINFO_ITEM* ni = m_board->FindNet( i );
  97. if( ni == NULL )
  98. continue;
  99. CLEARANCE_ENT ent;
  100. ent.coupledNet = DpCoupledNet( i );
  101. wxString netClassName = ni->GetClassName();
  102. NETCLASSPTR nc = m_board->GetDesignSettings().m_NetClasses.Find( netClassName );
  103. int clearance = nc->GetClearance();
  104. ent.clearance = clearance;
  105. m_netClearanceCache[i] = ent;
  106. wxLogTrace( "PNS", "Add net %u netclass %s clearance %d", i, netClassName.mb_str(), clearance );
  107. }
  108. // Build clearance cache for pads
  109. for( MODULE* mod = m_board->m_Modules; mod ; mod = mod->Next() )
  110. {
  111. auto moduleClearance = mod->GetLocalClearance();
  112. for( D_PAD* pad = mod->PadsList(); pad; pad = pad->Next() )
  113. {
  114. int padClearance = pad->GetLocalClearance();
  115. if( padClearance > 0 )
  116. m_localClearanceCache[ pad ] = padClearance;
  117. else if( moduleClearance > 0 )
  118. m_localClearanceCache[ pad ] = moduleClearance;
  119. }
  120. }
  121. //printf("DefaultCL : %d\n", m_board->GetDesignSettings().m_NetClasses.Find ("Default clearance")->GetClearance());
  122. m_overrideEnabled = false;
  123. m_defaultClearance = Millimeter2iu( 0.254 ); // m_board->m_NetClasses.Find ("Default clearance")->GetClearance();
  124. m_overrideNetA = 0;
  125. m_overrideNetB = 0;
  126. m_overrideClearance = 0;
  127. m_useDpGap = false;
  128. }
  129. PNS_PCBNEW_RULE_RESOLVER::~PNS_PCBNEW_RULE_RESOLVER()
  130. {
  131. }
  132. int PNS_PCBNEW_RULE_RESOLVER::localPadClearance( const PNS::ITEM* aItem ) const
  133. {
  134. if( !aItem->Parent() || aItem->Parent()->Type() != PCB_PAD_T )
  135. return 0;
  136. const D_PAD* pad = static_cast<D_PAD*>( aItem->Parent() );
  137. auto i = m_localClearanceCache.find( pad );
  138. if( i == m_localClearanceCache.end() )
  139. return 0;
  140. return i->second;
  141. }
  142. int PNS_PCBNEW_RULE_RESOLVER::Clearance( const PNS::ITEM* aA, const PNS::ITEM* aB ) const
  143. {
  144. int net_a = aA->Net();
  145. int cl_a = ( net_a >= 0 ? m_netClearanceCache[net_a].clearance : m_defaultClearance );
  146. int net_b = aB->Net();
  147. int cl_b = ( net_b >= 0 ? m_netClearanceCache[net_b].clearance : m_defaultClearance );
  148. bool linesOnly = aA->OfKind( PNS::ITEM::SEGMENT_T | PNS::ITEM::LINE_T )
  149. && aB->OfKind( PNS::ITEM::SEGMENT_T | PNS::ITEM::LINE_T );
  150. if( linesOnly && net_a >= 0 && net_b >= 0 && m_netClearanceCache[net_a].coupledNet == net_b )
  151. {
  152. cl_a = cl_b = m_router->Sizes().DiffPairGap() - 2 * PNS_HULL_MARGIN;
  153. }
  154. int pad_a = localPadClearance( aA );
  155. int pad_b = localPadClearance( aB );
  156. if( pad_a > 0 )
  157. cl_a = pad_a;
  158. if( pad_b > 0 )
  159. cl_b = pad_b;
  160. return std::max( cl_a, cl_b );
  161. }
  162. int PNS_PCBNEW_RULE_RESOLVER::Clearance( int aNetCode ) const
  163. {
  164. if( aNetCode > 0 && aNetCode < (int) m_netClearanceCache.size() )
  165. return m_netClearanceCache[aNetCode].clearance;
  166. return m_defaultClearance;
  167. }
  168. // fixme: ugly hack to make the optimizer respect gap width for currently routed differential pair.
  169. void PNS_PCBNEW_RULE_RESOLVER::OverrideClearance( bool aEnable, int aNetA, int aNetB , int aClearance )
  170. {
  171. m_overrideEnabled = aEnable;
  172. m_overrideNetA = aNetA;
  173. m_overrideNetB = aNetB;
  174. m_overrideClearance = aClearance;
  175. }
  176. int PNS_PCBNEW_RULE_RESOLVER::matchDpSuffix( wxString aNetName, wxString& aComplementNet, wxString& aBaseDpName )
  177. {
  178. int rv = 0;
  179. if( aNetName.EndsWith( "+" ) )
  180. {
  181. aComplementNet = "-";
  182. rv = 1;
  183. }
  184. else if( aNetName.EndsWith( "P" ) )
  185. {
  186. aComplementNet = "N";
  187. rv = 1;
  188. }
  189. else if( aNetName.EndsWith( "-" ) )
  190. {
  191. aComplementNet = "+";
  192. rv = -1;
  193. }
  194. else if( aNetName.EndsWith( "N" ) )
  195. {
  196. aComplementNet = "P";
  197. rv = -1;
  198. }
  199. // Match P followed by 2 digits
  200. else if( aNetName.Right( 2 ).IsNumber() && aNetName.Right( 3 ).Left( 1 ) == "P" )
  201. {
  202. aComplementNet = "N" + aNetName.Right( 2 );
  203. rv = 1;
  204. }
  205. // Match P followed by 1 digit
  206. else if( aNetName.Right( 1 ).IsNumber() && aNetName.Right( 2 ).Left( 1 ) == "P" )
  207. {
  208. aComplementNet = "N" + aNetName.Right( 1 );
  209. rv = 1;
  210. }
  211. // Match N followed by 2 digits
  212. else if( aNetName.Right( 2 ).IsNumber() && aNetName.Right( 3 ).Left( 1 ) == "N" )
  213. {
  214. aComplementNet = "P" + aNetName.Right( 2 );
  215. rv = -1;
  216. }
  217. // Match N followed by 1 digit
  218. else if( aNetName.Right( 1 ).IsNumber() && aNetName.Right( 2 ).Left( 1 ) == "N" )
  219. {
  220. aComplementNet = "P" + aNetName.Right( 1 );
  221. rv = -1;
  222. }
  223. if( rv != 0 )
  224. {
  225. aBaseDpName = aNetName.Left( aNetName.Length() - aComplementNet.Length() );
  226. aComplementNet = aBaseDpName + aComplementNet;
  227. }
  228. return rv;
  229. }
  230. int PNS_PCBNEW_RULE_RESOLVER::DpCoupledNet( int aNet )
  231. {
  232. wxString refName = m_board->FindNet( aNet )->GetNetname();
  233. wxString dummy, coupledNetName;
  234. if( matchDpSuffix( refName, coupledNetName, dummy ) )
  235. {
  236. NETINFO_ITEM* net = m_board->FindNet( coupledNetName );
  237. if( !net )
  238. return -1;
  239. return net->GetNet();
  240. }
  241. return -1;
  242. }
  243. int PNS_PCBNEW_RULE_RESOLVER::DpNetPolarity( int aNet )
  244. {
  245. wxString refName = m_board->FindNet( aNet )->GetNetname();
  246. wxString dummy1, dummy2;
  247. return matchDpSuffix( refName, dummy1, dummy2 );
  248. }
  249. bool PNS_PCBNEW_RULE_RESOLVER::DpNetPair( PNS::ITEM* aItem, int& aNetP, int& aNetN )
  250. {
  251. if( !aItem || !aItem->Parent() || !aItem->Parent()->GetNet() )
  252. return false;
  253. wxString netNameP = aItem->Parent()->GetNet()->GetNetname();
  254. wxString netNameN, netNameCoupled, netNameBase;
  255. int r = matchDpSuffix( netNameP, netNameCoupled, netNameBase );
  256. if( r == 0 )
  257. return false;
  258. else if( r == 1 )
  259. {
  260. netNameN = netNameCoupled;
  261. }
  262. else
  263. {
  264. netNameN = netNameP;
  265. netNameP = netNameCoupled;
  266. }
  267. // wxLogTrace( "PNS","p %s n %s base %s\n", (const char *)netNameP.c_str(), (const char *)netNameN.c_str(), (const char *)netNameBase.c_str() );
  268. NETINFO_ITEM* netInfoP = m_board->FindNet( netNameP );
  269. NETINFO_ITEM* netInfoN = m_board->FindNet( netNameN );
  270. //wxLogTrace( "PNS","ip %p in %p\n", netInfoP, netInfoN);
  271. if( !netInfoP || !netInfoN )
  272. return false;
  273. aNetP = netInfoP->GetNet();
  274. aNetN = netInfoN->GetNet();
  275. return true;
  276. }
  277. class PNS_PCBNEW_DEBUG_DECORATOR: public PNS::DEBUG_DECORATOR
  278. {
  279. public:
  280. PNS_PCBNEW_DEBUG_DECORATOR( KIGFX::VIEW* aView = NULL ): PNS::DEBUG_DECORATOR(),
  281. m_view( NULL ), m_items( NULL )
  282. {
  283. SetView( aView );
  284. }
  285. ~PNS_PCBNEW_DEBUG_DECORATOR()
  286. {
  287. Clear();
  288. delete m_items;
  289. }
  290. void SetView( KIGFX::VIEW* aView )
  291. {
  292. Clear();
  293. delete m_items;
  294. m_items = NULL;
  295. m_view = aView;
  296. if( m_view == NULL )
  297. return;
  298. m_items = new KIGFX::VIEW_GROUP( m_view );
  299. m_items->SetLayer( LAYER_GP_OVERLAY ) ;
  300. m_view->Add( m_items );
  301. }
  302. void AddPoint( VECTOR2I aP, int aColor ) override
  303. {
  304. SHAPE_LINE_CHAIN l;
  305. l.Append( aP - VECTOR2I( -50000, -50000 ) );
  306. l.Append( aP + VECTOR2I( -50000, -50000 ) );
  307. AddLine( l, aColor, 10000 );
  308. l.Clear();
  309. l.Append( aP - VECTOR2I( 50000, -50000 ) );
  310. l.Append( aP + VECTOR2I( 50000, -50000 ) );
  311. AddLine( l, aColor, 10000 );
  312. }
  313. void AddBox( BOX2I aB, int aColor ) override
  314. {
  315. SHAPE_LINE_CHAIN l;
  316. VECTOR2I o = aB.GetOrigin();
  317. VECTOR2I s = aB.GetSize();
  318. l.Append( o );
  319. l.Append( o.x + s.x, o.y );
  320. l.Append( o.x + s.x, o.y + s.y );
  321. l.Append( o.x, o.y + s.y );
  322. l.Append( o );
  323. AddLine( l, aColor, 10000 );
  324. }
  325. void AddSegment( SEG aS, int aColor ) override
  326. {
  327. SHAPE_LINE_CHAIN l;
  328. l.Append( aS.A );
  329. l.Append( aS.B );
  330. AddLine( l, aColor, 10000 );
  331. }
  332. void AddDirections( VECTOR2D aP, int aMask, int aColor ) override
  333. {
  334. BOX2I b( aP - VECTOR2I( 10000, 10000 ), VECTOR2I( 20000, 20000 ) );
  335. AddBox( b, aColor );
  336. for( int i = 0; i < 8; i++ )
  337. {
  338. if( ( 1 << i ) & aMask )
  339. {
  340. VECTOR2I v = DIRECTION_45( ( DIRECTION_45::Directions ) i ).ToVector() * 100000;
  341. AddSegment( SEG( aP, aP + v ), aColor );
  342. }
  343. }
  344. }
  345. void AddLine( const SHAPE_LINE_CHAIN& aLine, int aType, int aWidth ) override
  346. {
  347. ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( NULL, m_view );
  348. pitem->Line( aLine, aWidth, aType );
  349. m_items->Add( pitem ); // Should not be needed, as m_items has been passed as a parent group in alloc;
  350. m_view->Update( m_items );
  351. }
  352. void Clear() override
  353. {
  354. if( m_view && m_items )
  355. {
  356. m_items->FreeItems();
  357. m_view->Update( m_items );
  358. }
  359. }
  360. private:
  361. KIGFX::VIEW* m_view;
  362. KIGFX::VIEW_GROUP* m_items;
  363. };
  364. PNS::DEBUG_DECORATOR* PNS_KICAD_IFACE::GetDebugDecorator()
  365. {
  366. return m_debugDecorator;
  367. }
  368. PNS_KICAD_IFACE::PNS_KICAD_IFACE()
  369. {
  370. m_ruleResolver = nullptr;
  371. m_board = nullptr;
  372. m_frame = nullptr;
  373. m_view = nullptr;
  374. m_previewItems = nullptr;
  375. m_world = nullptr;
  376. m_router = nullptr;
  377. m_debugDecorator = nullptr;
  378. m_dispOptions = nullptr;
  379. }
  380. PNS_KICAD_IFACE::~PNS_KICAD_IFACE()
  381. {
  382. delete m_ruleResolver;
  383. delete m_debugDecorator;
  384. if( m_previewItems )
  385. {
  386. m_previewItems->FreeItems();
  387. delete m_previewItems;
  388. }
  389. }
  390. std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE::syncPad( D_PAD* aPad )
  391. {
  392. LAYER_RANGE layers( 0, MAX_CU_LAYERS - 1 );
  393. // ignore non-copper pads
  394. if( ( aPad->GetLayerSet() & LSET::AllCuMask()).none() )
  395. return NULL;
  396. switch( aPad->GetAttribute() )
  397. {
  398. case PAD_ATTRIB_STANDARD:
  399. break;
  400. case PAD_ATTRIB_SMD:
  401. case PAD_ATTRIB_HOLE_NOT_PLATED:
  402. case PAD_ATTRIB_CONN:
  403. {
  404. LSET lmsk = aPad->GetLayerSet();
  405. bool is_copper = false;
  406. for( int i = 0; i < MAX_CU_LAYERS; i++ )
  407. {
  408. if( lmsk[i] )
  409. {
  410. is_copper = true;
  411. if( aPad->GetAttribute() != PAD_ATTRIB_HOLE_NOT_PLATED )
  412. layers = LAYER_RANGE( i );
  413. break;
  414. }
  415. }
  416. if( !is_copper )
  417. return NULL;
  418. }
  419. break;
  420. default:
  421. wxLogTrace( "PNS", "unsupported pad type 0x%x", aPad->GetAttribute() );
  422. return NULL;
  423. }
  424. std::unique_ptr< PNS::SOLID > solid( new PNS::SOLID );
  425. solid->SetLayers( layers );
  426. solid->SetNet( aPad->GetNetCode() );
  427. solid->SetParent( aPad );
  428. wxPoint wx_c = aPad->ShapePos();
  429. wxSize wx_sz = aPad->GetSize();
  430. wxPoint offset = aPad->GetOffset();
  431. VECTOR2I c( wx_c.x, wx_c.y );
  432. VECTOR2I sz( wx_sz.x, wx_sz.y );
  433. RotatePoint( &offset, aPad->GetOrientation() );
  434. solid->SetPos( VECTOR2I( c.x - offset.x, c.y - offset.y ) );
  435. solid->SetOffset( VECTOR2I( offset.x, offset.y ) );
  436. double orient = aPad->GetOrientation() / 10.0;
  437. if( aPad->GetShape() == PAD_SHAPE_CIRCLE )
  438. {
  439. solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
  440. }
  441. else
  442. {
  443. if( orient == 0.0 || orient == 90.0 || orient == 180.0 || orient == 270.0 )
  444. {
  445. if( orient == 90.0 || orient == 270.0 )
  446. sz = VECTOR2I( sz.y, sz.x );
  447. switch( aPad->GetShape() )
  448. {
  449. case PAD_SHAPE_OVAL:
  450. if( sz.x == sz.y )
  451. solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
  452. else
  453. {
  454. VECTOR2I delta;
  455. if( sz.x > sz.y )
  456. delta = VECTOR2I( ( sz.x - sz.y ) / 2, 0 );
  457. else
  458. delta = VECTOR2I( 0, ( sz.y - sz.x ) / 2 );
  459. SHAPE_SEGMENT* shape = new SHAPE_SEGMENT( c - delta, c + delta,
  460. std::min( sz.x, sz.y ) );
  461. solid->SetShape( shape );
  462. }
  463. break;
  464. case PAD_SHAPE_RECT:
  465. solid->SetShape( new SHAPE_RECT( c - sz / 2, sz.x, sz.y ) );
  466. break;
  467. case PAD_SHAPE_TRAPEZOID:
  468. {
  469. wxPoint coords[4];
  470. aPad->BuildPadPolygon( coords, wxSize( 0, 0 ), aPad->GetOrientation() );
  471. SHAPE_CONVEX* shape = new SHAPE_CONVEX();
  472. for( int ii = 0; ii < 4; ii++ )
  473. {
  474. shape->Append( wx_c + coords[ii] );
  475. }
  476. solid->SetShape( shape );
  477. break;
  478. }
  479. case PAD_SHAPE_ROUNDRECT:
  480. {
  481. SHAPE_POLY_SET outline;
  482. const int segmentToCircleCount = 64;
  483. aPad->BuildPadShapePolygon( outline, wxSize( 0, 0 ), segmentToCircleCount, 1.0 );
  484. // TransformRoundRectToPolygon creates only one convex polygon
  485. SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
  486. SHAPE_CONVEX* shape = new SHAPE_CONVEX();
  487. for( int ii = 0; ii < poly.PointCount(); ++ii )
  488. {
  489. shape->Append( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );
  490. }
  491. solid->SetShape( shape );
  492. }
  493. break;
  494. case PAD_SHAPE_CUSTOM:
  495. {
  496. SHAPE_POLY_SET outline;
  497. outline.Append( aPad->GetCustomShapeAsPolygon() );
  498. aPad->CustomShapeAsPolygonToBoardPosition( &outline, wx_c, aPad->GetOrientation() );
  499. for( int jj = 0; jj < outline.OutlineCount(); ++jj )
  500. {
  501. SHAPE_CONVEX* shape = new SHAPE_CONVEX();
  502. const SHAPE_LINE_CHAIN& poly = outline.COutline( jj );
  503. for( int ii = 0; ii < poly.PointCount(); ii++ )
  504. shape->Append( wxPoint( poly.CPoint( ii ).x, poly.CPoint( ii ).y ) );
  505. solid->SetShape( shape );
  506. }
  507. break;
  508. }
  509. default:
  510. wxLogTrace( "PNS", "unsupported pad shape" );
  511. return nullptr;
  512. }
  513. }
  514. else
  515. {
  516. switch( aPad->GetShape() )
  517. {
  518. // PAD_SHAPE_CIRCLE already handled above
  519. case PAD_SHAPE_OVAL:
  520. if( sz.x == sz.y )
  521. solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
  522. else
  523. {
  524. wxPoint start;
  525. wxPoint end;
  526. wxPoint corner;
  527. SHAPE_CONVEX* shape = new SHAPE_CONVEX();
  528. int w = aPad->BuildSegmentFromOvalShape( start, end, 0.0, wxSize( 0, 0 ) );
  529. if( start.y == 0 )
  530. corner = wxPoint( start.x, -( w / 2 ) );
  531. else
  532. corner = wxPoint( w / 2, start.y );
  533. RotatePoint( &start, aPad->GetOrientation() );
  534. RotatePoint( &corner, aPad->GetOrientation() );
  535. shape->Append( wx_c + corner );
  536. for( int rot = 100; rot <= 1800; rot += 100 )
  537. {
  538. wxPoint p( corner );
  539. RotatePoint( &p, start, rot );
  540. shape->Append( wx_c + p );
  541. }
  542. if( end.y == 0 )
  543. corner = wxPoint( end.x, w / 2 );
  544. else
  545. corner = wxPoint( -( w / 2 ), end.y );
  546. RotatePoint( &end, aPad->GetOrientation() );
  547. RotatePoint( &corner, aPad->GetOrientation() );
  548. shape->Append( wx_c + corner );
  549. for( int rot = 100; rot <= 1800; rot += 100 )
  550. {
  551. wxPoint p( corner );
  552. RotatePoint( &p, end, rot );
  553. shape->Append( wx_c + p );
  554. }
  555. solid->SetShape( shape );
  556. }
  557. break;
  558. case PAD_SHAPE_RECT:
  559. case PAD_SHAPE_TRAPEZOID:
  560. {
  561. wxPoint coords[4];
  562. aPad->BuildPadPolygon( coords, wxSize( 0, 0 ), aPad->GetOrientation() );
  563. SHAPE_CONVEX* shape = new SHAPE_CONVEX();
  564. for( int ii = 0; ii < 4; ii++ )
  565. {
  566. shape->Append( wx_c + coords[ii] );
  567. }
  568. solid->SetShape( shape );
  569. break;
  570. }
  571. case PAD_SHAPE_ROUNDRECT:
  572. {
  573. SHAPE_POLY_SET outline;
  574. const int segmentToCircleCount = 32;
  575. aPad->BuildPadShapePolygon( outline, wxSize( 0, 0 ),
  576. segmentToCircleCount, 1.0 );
  577. // TransformRoundRectToPolygon creates only one convex polygon
  578. SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
  579. SHAPE_CONVEX* shape = new SHAPE_CONVEX();
  580. for( int ii = 0; ii < poly.PointCount(); ++ii )
  581. {
  582. shape->Append( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );
  583. }
  584. solid->SetShape( shape );
  585. break;
  586. }
  587. case PAD_SHAPE_CUSTOM:
  588. {
  589. SHAPE_POLY_SET outline;
  590. outline.Append( aPad->GetCustomShapeAsPolygon() );
  591. aPad->CustomShapeAsPolygonToBoardPosition( &outline, wx_c, aPad->GetOrientation() );
  592. for( int jj = 0; jj < outline.OutlineCount(); ++jj )
  593. {
  594. SHAPE_CONVEX* shape = new SHAPE_CONVEX();
  595. const SHAPE_LINE_CHAIN& poly = outline.COutline( jj );
  596. for( int ii = 0; ii < poly.PointCount(); ii++ )
  597. shape->Append( wxPoint( poly.CPoint( ii ).x, poly.CPoint( ii ).y ) );
  598. solid->SetShape( shape );
  599. }
  600. break;
  601. }
  602. default:
  603. wxLogTrace( "PNS", "unsupported pad shape" );
  604. return nullptr;
  605. }
  606. }
  607. }
  608. return solid;
  609. }
  610. std::unique_ptr<PNS::SEGMENT> PNS_KICAD_IFACE::syncTrack( TRACK* aTrack )
  611. {
  612. std::unique_ptr< PNS::SEGMENT > segment(
  613. new PNS::SEGMENT( SEG( aTrack->GetStart(), aTrack->GetEnd() ), aTrack->GetNetCode() )
  614. );
  615. segment->SetWidth( aTrack->GetWidth() );
  616. segment->SetLayers( LAYER_RANGE( aTrack->GetLayer() ) );
  617. segment->SetParent( aTrack );
  618. if( aTrack->IsLocked() )
  619. segment->Mark( PNS::MK_LOCKED );
  620. return segment;
  621. }
  622. std::unique_ptr<PNS::VIA> PNS_KICAD_IFACE::syncVia( VIA* aVia )
  623. {
  624. PCB_LAYER_ID top, bottom;
  625. aVia->LayerPair( &top, &bottom );
  626. std::unique_ptr<PNS::VIA> via( new PNS::VIA(
  627. aVia->GetPosition(),
  628. LAYER_RANGE( top, bottom ),
  629. aVia->GetWidth(),
  630. aVia->GetDrillValue(),
  631. aVia->GetNetCode(),
  632. aVia->GetViaType() )
  633. );
  634. via->SetParent( aVia );
  635. if( aVia->IsLocked() )
  636. via->Mark( PNS::MK_LOCKED );
  637. return via;
  638. }
  639. void PNS_KICAD_IFACE::SetBoard( BOARD* aBoard )
  640. {
  641. m_board = aBoard;
  642. wxLogTrace( "PNS", "m_board = %p", m_board );
  643. }
  644. void PNS_KICAD_IFACE::SyncWorld( PNS::NODE *aWorld )
  645. {
  646. if( !m_board )
  647. {
  648. wxLogTrace( "PNS", "No board attached, aborting sync." );
  649. return;
  650. }
  651. for( MODULE* module = m_board->m_Modules; module; module = module->Next() )
  652. {
  653. for( D_PAD* pad = module->PadsList(); pad; pad = pad->Next() )
  654. {
  655. std::unique_ptr< PNS::SOLID > solid = syncPad( pad );
  656. if( solid )
  657. aWorld->Add( std::move( solid ) );
  658. }
  659. }
  660. for( TRACK* t = m_board->m_Track; t; t = t->Next() )
  661. {
  662. KICAD_T type = t->Type();
  663. if( type == PCB_TRACE_T ) {
  664. std::unique_ptr< PNS::SEGMENT > segment = syncTrack( t );
  665. if( segment ) {
  666. aWorld->Add( std::move( segment ) );
  667. }
  668. } else if( type == PCB_VIA_T ) {
  669. std::unique_ptr< PNS::VIA > via = syncVia( static_cast<VIA*>( t ) );
  670. if( via ) {
  671. aWorld->Add( std::move( via ) );
  672. }
  673. }
  674. }
  675. int worstClearance = m_board->GetDesignSettings().GetBiggestClearanceValue();
  676. delete m_ruleResolver;
  677. m_ruleResolver = new PNS_PCBNEW_RULE_RESOLVER( m_board, m_router );
  678. aWorld->SetRuleResolver( m_ruleResolver );
  679. aWorld->SetMaxClearance( 4 * worstClearance );
  680. }
  681. void PNS_KICAD_IFACE::EraseView()
  682. {
  683. for( auto item : m_hiddenItems )
  684. m_view->SetVisible( item, true );
  685. m_hiddenItems.clear();
  686. if( m_previewItems )
  687. {
  688. m_previewItems->FreeItems();
  689. m_view->Update( m_previewItems );
  690. }
  691. if( m_debugDecorator )
  692. m_debugDecorator->Clear();
  693. }
  694. void PNS_KICAD_IFACE::DisplayItem( const PNS::ITEM* aItem, int aColor, int aClearance )
  695. {
  696. wxLogTrace( "PNS", "DisplayItem %p", aItem );
  697. ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aItem, m_view );
  698. if( aColor >= 0 )
  699. pitem->SetColor( KIGFX::COLOR4D( aColor ) );
  700. if( aClearance >= 0 )
  701. {
  702. pitem->SetClearance( aClearance );
  703. if( m_dispOptions )
  704. {
  705. auto clearanceDisp = m_dispOptions->m_ShowTrackClearanceMode;
  706. pitem->ShowTrackClearance( clearanceDisp != PCB_DISPLAY_OPTIONS::DO_NOT_SHOW_CLEARANCE );
  707. pitem->ShowViaClearance( clearanceDisp != PCB_DISPLAY_OPTIONS::DO_NOT_SHOW_CLEARANCE
  708. && clearanceDisp != PCB_DISPLAY_OPTIONS::SHOW_CLEARANCE_NEW_TRACKS );
  709. }
  710. }
  711. m_previewItems->Add( pitem );
  712. m_view->Update( m_previewItems );
  713. }
  714. void PNS_KICAD_IFACE::HideItem( PNS::ITEM* aItem )
  715. {
  716. BOARD_CONNECTED_ITEM* parent = aItem->Parent();
  717. if( parent )
  718. {
  719. if( m_view->IsVisible( parent ) )
  720. m_hiddenItems.insert( parent );
  721. m_view->SetVisible( parent, false );
  722. m_view->Update( parent, KIGFX::APPEARANCE );
  723. }
  724. }
  725. void PNS_KICAD_IFACE::RemoveItem( PNS::ITEM* aItem )
  726. {
  727. BOARD_CONNECTED_ITEM* parent = aItem->Parent();
  728. if( parent )
  729. {
  730. m_commit->Remove( parent );
  731. }
  732. }
  733. void PNS_KICAD_IFACE::AddItem( PNS::ITEM* aItem )
  734. {
  735. BOARD_CONNECTED_ITEM* newBI = NULL;
  736. switch( aItem->Kind() )
  737. {
  738. case PNS::ITEM::SEGMENT_T:
  739. {
  740. PNS::SEGMENT* seg = static_cast<PNS::SEGMENT*>( aItem );
  741. TRACK* track = new TRACK( m_board );
  742. const SEG& s = seg->Seg();
  743. track->SetStart( wxPoint( s.A.x, s.A.y ) );
  744. track->SetEnd( wxPoint( s.B.x, s.B.y ) );
  745. track->SetWidth( seg->Width() );
  746. track->SetLayer( ToLAYER_ID( seg->Layers().Start() ) );
  747. track->SetNetCode( seg->Net() > 0 ? seg->Net() : 0 );
  748. newBI = track;
  749. break;
  750. }
  751. case PNS::ITEM::VIA_T:
  752. {
  753. VIA* via_board = new VIA( m_board );
  754. PNS::VIA* via = static_cast<PNS::VIA*>( aItem );
  755. via_board->SetPosition( wxPoint( via->Pos().x, via->Pos().y ) );
  756. via_board->SetWidth( via->Diameter() );
  757. via_board->SetDrill( via->Drill() );
  758. via_board->SetNetCode( via->Net() > 0 ? via->Net() : 0 );
  759. via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
  760. via_board->SetLayerPair( ToLAYER_ID( via->Layers().Start() ),
  761. ToLAYER_ID( via->Layers().End() ) );
  762. newBI = via_board;
  763. break;
  764. }
  765. default:
  766. break;
  767. }
  768. if( newBI )
  769. {
  770. aItem->SetParent( newBI );
  771. newBI->ClearFlags();
  772. m_commit->Add( newBI );
  773. }
  774. }
  775. void PNS_KICAD_IFACE::Commit()
  776. {
  777. EraseView();
  778. m_commit->Push( wxT( "Added a track" ) );
  779. m_commit.reset( new BOARD_COMMIT( m_frame ) );
  780. }
  781. void PNS_KICAD_IFACE::SetView( KIGFX::VIEW* aView )
  782. {
  783. wxLogTrace( "PNS", "SetView %p", aView );
  784. if( m_previewItems )
  785. {
  786. m_previewItems->FreeItems();
  787. delete m_previewItems;
  788. }
  789. m_view = aView;
  790. m_previewItems = new KIGFX::VIEW_GROUP( m_view );
  791. m_previewItems->SetLayer( LAYER_GP_OVERLAY ) ;
  792. m_view->Add( m_previewItems );
  793. delete m_debugDecorator;
  794. m_debugDecorator = new PNS_PCBNEW_DEBUG_DECORATOR();
  795. m_debugDecorator->SetView( m_view );
  796. }
  797. void PNS_KICAD_IFACE::UpdateNet( int aNetCode )
  798. {
  799. wxLogTrace( "PNS", "Update-net %d", aNetCode );
  800. }
  801. PNS::RULE_RESOLVER* PNS_KICAD_IFACE::GetRuleResolver()
  802. {
  803. return m_ruleResolver;
  804. }
  805. void PNS_KICAD_IFACE::SetRouter( PNS::ROUTER* aRouter )
  806. {
  807. m_router = aRouter;
  808. }
  809. void PNS_KICAD_IFACE::SetHostFrame( PCB_EDIT_FRAME* aFrame )
  810. {
  811. m_frame = aFrame;
  812. m_commit.reset( new BOARD_COMMIT( m_frame ) );
  813. m_dispOptions = (PCB_DISPLAY_OPTIONS*) m_frame->GetDisplayOptions();
  814. }