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.

1180 lines
33 KiB

19 years ago
18 years ago
18 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
19 years ago
  1. /*******************************************/
  2. /* class_board.cpp - BOARD class functions */
  3. /*******************************************/
  4. #include "fctsys.h"
  5. #include "common.h"
  6. #include "pcbnew.h"
  7. /* This is an odd place for this, but cvpcb won't link if it is
  8. * in class_board_item.cpp like I first tried it.
  9. */
  10. wxPoint BOARD_ITEM::ZeroOffset( 0, 0 );
  11. /*****************/
  12. /* Class BOARD: */
  13. /*****************/
  14. /* Constructor */
  15. BOARD::BOARD( EDA_BaseStruct* parent, WinEDA_BasePcbFrame* frame ) :
  16. BOARD_ITEM( (BOARD_ITEM*)parent, TYPE_PCB )
  17. {
  18. m_PcbFrame = frame;
  19. m_Status_Pcb = 0; // Mot d'etat: Bit 1 = Chevelu calcule
  20. m_BoardSettings = &g_DesignSettings;
  21. m_NbNodes = 0; // nombre de pads connectes
  22. m_NbNoconnect = 0; // nombre de chevelus actifs
  23. m_CurrentZoneContour = NULL; // This ZONE_CONTAINER handle the zone contour cuurently in progress
  24. m_NetInfo = new NETINFO_LIST( this ); // handle nets info list (name, design constraints ..
  25. for( int layer = 0; layer<NB_COPPER_LAYERS; ++layer )
  26. {
  27. m_Layer[layer].m_Name = ReturnPcbLayerName( layer, true );
  28. m_Layer[layer].m_Type = LT_SIGNAL;
  29. }
  30. }
  31. /***************/
  32. /* Destructeur */
  33. /***************/
  34. BOARD::~BOARD()
  35. {
  36. while( m_ZoneDescriptorList.size() )
  37. {
  38. ZONE_CONTAINER* area_to_remove = m_ZoneDescriptorList[0];
  39. Delete( area_to_remove );
  40. }
  41. m_FullRatsnest.clear();
  42. m_LocalRatsnest.clear();
  43. DeleteMARKERs();
  44. DeleteZONEOutlines();
  45. delete m_CurrentZoneContour;
  46. m_CurrentZoneContour = NULL;
  47. delete m_NetInfo;
  48. }
  49. wxString BOARD::GetLayerName( int aLayerIndex ) const
  50. {
  51. // copper layer names are stored in the BOARD.
  52. if( (unsigned) aLayerIndex < (unsigned) GetCopperLayerCount()
  53. || aLayerIndex == LAST_COPPER_LAYER )
  54. {
  55. // default names were set in BOARD::BOARD() but they may be
  56. // over-ridden by BOARD::SetLayerName()
  57. return m_Layer[aLayerIndex].m_Name;
  58. }
  59. return ReturnPcbLayerName( aLayerIndex, true );
  60. }
  61. bool BOARD::SetLayerName( int aLayerIndex, const wxString& aLayerName )
  62. {
  63. if( (unsigned) aLayerIndex < (unsigned) GetCopperLayerCount()
  64. || aLayerIndex==LAST_COPPER_LAYER )
  65. {
  66. if( aLayerName == wxEmptyString || aLayerName.Len() > 20 )
  67. return false;
  68. // no quote chars in the name allowed
  69. if( aLayerName.Find( wxChar( '"' ) ) != wxNOT_FOUND )
  70. return false;
  71. // ensure unique-ness of layer names
  72. for( int layer = 0; layer<GetCopperLayerCount() || layer==LAST_COPPER_LAYER; )
  73. {
  74. if( layer!=aLayerIndex && aLayerName == m_Layer[layer].m_Name )
  75. return false;
  76. if( ++layer == GetCopperLayerCount() )
  77. layer = LAST_COPPER_LAYER;
  78. }
  79. m_Layer[aLayerIndex].m_Name = aLayerName;
  80. // replace any spaces with underscores
  81. m_Layer[aLayerIndex].m_Name.Replace( wxT( " " ), wxT( "_" ) );
  82. return true;
  83. }
  84. return false;
  85. }
  86. LAYER_T BOARD::GetLayerType( int aLayerIndex ) const
  87. {
  88. if( (unsigned) aLayerIndex < (unsigned) GetCopperLayerCount() )
  89. return m_Layer[aLayerIndex].m_Type;
  90. return LT_SIGNAL;
  91. }
  92. bool BOARD::SetLayerType( int aLayerIndex, LAYER_T aLayerType )
  93. {
  94. if( (unsigned) aLayerIndex < (unsigned) GetCopperLayerCount() )
  95. {
  96. m_Layer[aLayerIndex].m_Type = aLayerType;
  97. return true;
  98. }
  99. return false;
  100. }
  101. const char* LAYER::ShowType( LAYER_T aType )
  102. {
  103. const char* cp;
  104. switch( aType )
  105. {
  106. default:
  107. case LT_SIGNAL:
  108. cp = "signal"; break;
  109. case LT_POWER:
  110. cp = "power"; break;
  111. case LT_MIXED:
  112. cp = "mixed"; break;
  113. case LT_JUMPER:
  114. cp = "jumper"; break;
  115. }
  116. return cp;
  117. }
  118. LAYER_T LAYER::ParseType( const char* aType )
  119. {
  120. if( strcmp( aType, "signal" ) == 0 )
  121. return LT_SIGNAL;
  122. else if( strcmp( aType, "power" ) == 0 )
  123. return LT_POWER;
  124. else if( strcmp( aType, "mixed" ) == 0 )
  125. return LT_MIXED;
  126. else if( strcmp( aType, "jumper" ) == 0 )
  127. return LT_JUMPER;
  128. else
  129. return LAYER_T( -1 );
  130. }
  131. int BOARD::GetCopperLayerCount() const
  132. {
  133. return m_BoardSettings->m_CopperLayerCount;
  134. }
  135. wxPoint& BOARD::GetPosition()
  136. {
  137. static wxPoint dummy( 0, 0 );
  138. return dummy; // a reference
  139. }
  140. void BOARD::Add( BOARD_ITEM* aBoardItem, int aControl )
  141. {
  142. if( aBoardItem == NULL )
  143. {
  144. wxFAIL_MSG( wxT( "BOARD::Add() param error: aBoardItem NULL" ) );
  145. return;
  146. }
  147. switch( aBoardItem->Type() )
  148. {
  149. // this one uses a vector
  150. case TYPE_MARKER:
  151. aBoardItem->SetParent( this );
  152. m_markers.push_back( (MARKER*) aBoardItem );
  153. break;
  154. // this one uses a vector
  155. case TYPE_ZONE_CONTAINER:
  156. aBoardItem->SetParent( this );
  157. m_ZoneDescriptorList.push_back( (ZONE_CONTAINER*) aBoardItem );
  158. break;
  159. case TYPE_TRACK:
  160. case TYPE_VIA:
  161. {
  162. TRACK* insertAid = ( (TRACK*) aBoardItem )->GetBestInsertPoint( this );
  163. m_Track.Insert( (TRACK*) aBoardItem, insertAid );
  164. }
  165. break;
  166. case TYPE_ZONE:
  167. if( aControl & ADD_APPEND )
  168. m_Zone.PushBack( (SEGZONE*) aBoardItem );
  169. else
  170. m_Zone.PushFront( (SEGZONE*) aBoardItem );
  171. aBoardItem->SetParent( this );
  172. break;
  173. case TYPE_MODULE:
  174. if( aControl & ADD_APPEND )
  175. m_Modules.PushBack( (MODULE*) aBoardItem );
  176. else
  177. m_Modules.PushFront( (MODULE*) aBoardItem );
  178. aBoardItem->SetParent( this );
  179. // Because the list of pads has changed, reset the status
  180. // This indicate the list of pad and nets must be recalculated before use
  181. m_Status_Pcb = 0;
  182. break;
  183. case TYPE_COTATION:
  184. case TYPE_DRAWSEGMENT:
  185. case TYPE_TEXTE:
  186. case TYPE_EDGE_MODULE:
  187. case TYPE_MIRE:
  188. if( aControl & ADD_APPEND )
  189. m_Drawings.PushBack( aBoardItem );
  190. else
  191. m_Drawings.PushFront( aBoardItem );
  192. aBoardItem->SetParent( this );
  193. break;
  194. // other types may use linked list
  195. default:
  196. wxFAIL_MSG( wxT( "BOARD::Add() needs work: BOARD_ITEM type not handled" ) );
  197. }
  198. }
  199. BOARD_ITEM* BOARD::Remove( BOARD_ITEM* aBoardItem )
  200. {
  201. // find these calls and fix them! Don't send me no stinkin' NULL.
  202. wxASSERT( aBoardItem );
  203. switch( aBoardItem->Type() )
  204. {
  205. case TYPE_MARKER:
  206. // find the item in the vector, then remove it
  207. for( unsigned i = 0; i<m_markers.size(); ++i )
  208. {
  209. if( m_markers[i] == (MARKER*) aBoardItem )
  210. {
  211. m_markers.erase( m_markers.begin() + i );
  212. break;
  213. }
  214. }
  215. break;
  216. case TYPE_ZONE_CONTAINER: // this one uses a vector
  217. // find the item in the vector, then delete then erase it.
  218. for( unsigned i = 0; i<m_ZoneDescriptorList.size(); ++i )
  219. {
  220. if( m_ZoneDescriptorList[i] == (ZONE_CONTAINER*) aBoardItem )
  221. {
  222. m_ZoneDescriptorList.erase( m_ZoneDescriptorList.begin() + i );
  223. break;
  224. }
  225. }
  226. break;
  227. case TYPE_MODULE:
  228. m_Modules.Remove( (MODULE*) aBoardItem );
  229. break;
  230. case TYPE_TRACK:
  231. case TYPE_VIA:
  232. m_Track.Remove( (TRACK*) aBoardItem );
  233. break;
  234. case TYPE_ZONE:
  235. m_Zone.Remove( (SEGZONE*) aBoardItem );
  236. break;
  237. case TYPE_COTATION:
  238. case TYPE_DRAWSEGMENT:
  239. case TYPE_TEXTE:
  240. case TYPE_EDGE_MODULE:
  241. case TYPE_MIRE:
  242. m_Drawings.Remove( aBoardItem );
  243. break;
  244. // other types may use linked list
  245. default:
  246. wxFAIL_MSG( wxT( "BOARD::Remove() needs more ::Type() support" ) );
  247. }
  248. return aBoardItem;
  249. }
  250. void BOARD::DeleteMARKERs()
  251. {
  252. // the vector does not know how to delete the MARKER, it holds pointers
  253. for( unsigned i = 0; i<m_markers.size(); ++i )
  254. delete m_markers[i];
  255. m_markers.clear();
  256. }
  257. void BOARD::DeleteZONEOutlines()
  258. {
  259. // the vector does not know how to delete the ZONE Outlines, it holds pointers
  260. for( unsigned i = 0; i<m_ZoneDescriptorList.size(); ++i )
  261. delete m_ZoneDescriptorList[i];
  262. m_ZoneDescriptorList.clear();
  263. }
  264. /* Calculate the track segment count */
  265. int BOARD::GetNumSegmTrack()
  266. {
  267. return m_Track.GetCount();
  268. }
  269. /* Calculate the zone segment count */
  270. int BOARD::GetNumSegmZone()
  271. {
  272. return m_Zone.GetCount();
  273. }
  274. // return the unconnection count
  275. unsigned BOARD::GetNoconnectCount()
  276. {
  277. return m_NbNoconnect;
  278. }
  279. // return the active pad count ( pads with a netcode > 0 )
  280. unsigned BOARD::GetNodesCount()
  281. {
  282. return m_NbNodes;
  283. }
  284. /***********************************/
  285. bool BOARD::ComputeBoundaryBox()
  286. /***********************************/
  287. /** Function ComputeBoundaryBox()
  288. * Calculate the bounding box of the board
  289. * This box contains pcb edges, pads , vias and tracks
  290. * Update m_PcbBox member
  291. *
  292. * @return 0 for an empty board (no items), else 1
  293. */
  294. {
  295. int rayon, cx, cy, d, xmin, ymin, xmax, ymax;
  296. bool hasItems = FALSE;
  297. EDA_BaseStruct* PtStruct;
  298. DRAWSEGMENT* ptr;
  299. xmin = ymin = 0x7FFFFFFFl;
  300. xmax = ymax = -0x7FFFFFFFl;
  301. /* Analyse PCB edges*/
  302. PtStruct = m_Drawings;
  303. for( ; PtStruct != NULL; PtStruct = PtStruct->Next() )
  304. {
  305. if( PtStruct->Type() != TYPE_DRAWSEGMENT )
  306. continue;
  307. ptr = (DRAWSEGMENT*) PtStruct;
  308. d = (ptr->m_Width / 2) + 1;
  309. if( ptr->m_Shape == S_CIRCLE )
  310. {
  311. cx = ptr->m_Start.x; cy = ptr->m_Start.y;
  312. rayon = (int) hypot( (double) ( ptr->m_End.x - cx ), (double) ( ptr->m_End.y - cy ) );
  313. rayon += d;
  314. xmin = MIN( xmin, cx - rayon );
  315. ymin = MIN( ymin, cy - rayon );
  316. xmax = MAX( xmax, cx + rayon );
  317. ymax = MAX( ymax, cy + rayon );
  318. hasItems = TRUE;
  319. }
  320. else
  321. {
  322. cx = MIN( ptr->m_Start.x, ptr->m_End.x );
  323. cy = MIN( ptr->m_Start.y, ptr->m_End.y );
  324. xmin = MIN( xmin, cx - d );
  325. ymin = MIN( ymin, cy - d );
  326. cx = MAX( ptr->m_Start.x, ptr->m_End.x );
  327. cy = MAX( ptr->m_Start.y, ptr->m_End.y );
  328. xmax = MAX( xmax, cx + d );
  329. ymax = MAX( ymax, cy + d );
  330. hasItems = TRUE;
  331. }
  332. }
  333. /* Analyse footprints */
  334. for( MODULE* module = m_Modules; module; module = module->Next() )
  335. {
  336. hasItems = TRUE;
  337. xmin = MIN( xmin, ( module->m_Pos.x + module->m_BoundaryBox.GetX() ) );
  338. ymin = MIN( ymin, ( module->m_Pos.y + module->m_BoundaryBox.GetY() ) );
  339. xmax = MAX( xmax, module->m_Pos.x + module->m_BoundaryBox.GetRight() );
  340. ymax = MAX( ymax, module->m_Pos.y + module->m_BoundaryBox.GetBottom() );
  341. for( D_PAD* pt_pad = module->m_Pads; pt_pad; pt_pad = pt_pad->Next() )
  342. {
  343. const wxPoint& pos = pt_pad->GetPosition();
  344. d = pt_pad->m_Rayon;
  345. xmin = MIN( xmin, pos.x - d );
  346. ymin = MIN( ymin, pos.y - d );
  347. xmax = MAX( xmax, pos.x + d );
  348. ymax = MAX( ymax, pos.y + d );
  349. }
  350. }
  351. /* Analyse track and zones */
  352. for( TRACK* track = m_Track; track; track = track->Next() )
  353. {
  354. d = (track->m_Width / 2) + 1;
  355. cx = MIN( track->m_Start.x, track->m_End.x );
  356. cy = MIN( track->m_Start.y, track->m_End.y );
  357. xmin = MIN( xmin, cx - d );
  358. ymin = MIN( ymin, cy - d );
  359. cx = MAX( track->m_Start.x, track->m_End.x );
  360. cy = MAX( track->m_Start.y, track->m_End.y );
  361. xmax = MAX( xmax, cx + d );
  362. ymax = MAX( ymax, cy + d );
  363. hasItems = TRUE;
  364. }
  365. for( TRACK* track = m_Zone; track; track = track->Next() )
  366. {
  367. d = (track->m_Width / 2) + 1;
  368. cx = MIN( track->m_Start.x, track->m_End.x );
  369. cy = MIN( track->m_Start.y, track->m_End.y );
  370. xmin = MIN( xmin, cx - d );
  371. ymin = MIN( ymin, cy - d );
  372. cx = MAX( track->m_Start.x, track->m_End.x );
  373. cy = MAX( track->m_Start.y, track->m_End.y );
  374. xmax = MAX( xmax, cx + d );
  375. ymax = MAX( ymax, cy + d );
  376. hasItems = TRUE;
  377. }
  378. if( !hasItems && m_PcbFrame )
  379. {
  380. if( m_PcbFrame->m_Draw_Sheet_Ref )
  381. {
  382. xmin = ymin = 0;
  383. xmax = m_PcbFrame->GetScreen()->ReturnPageSize().x;
  384. ymax = m_PcbFrame->GetScreen()->ReturnPageSize().y;
  385. }
  386. else
  387. {
  388. xmin = -m_PcbFrame->GetScreen()->ReturnPageSize().x / 2;
  389. ymin = -m_PcbFrame->GetScreen()->ReturnPageSize().y / 2;
  390. xmax = m_PcbFrame->GetScreen()->ReturnPageSize().x / 2;
  391. ymax = m_PcbFrame->GetScreen()->ReturnPageSize().y / 2;
  392. }
  393. }
  394. m_BoundaryBox.SetX( xmin );
  395. m_BoundaryBox.SetY( ymin );
  396. m_BoundaryBox.SetWidth( xmax - xmin );
  397. m_BoundaryBox.SetHeight( ymax - ymin );
  398. return hasItems;
  399. }
  400. // virtual, see pcbstruct.h
  401. void BOARD::DisplayInfo( WinEDA_DrawFrame* frame )
  402. {
  403. /* Affiche l'etat du PCB : nb de pads, nets , connexions.. */
  404. #define POS_AFF_NBPADS 1
  405. #define POS_AFF_NBVIAS 8
  406. #define POS_AFF_NBNODES 16
  407. #define POS_AFF_NBNETS 24
  408. #define POS_AFF_NBLINKS 32
  409. #define POS_AFF_NBCONNECT 40
  410. #define POS_AFF_NBNOCONNECT 48
  411. wxString txt;
  412. frame->MsgPanel->EraseMsgBox();
  413. int viasCount = 0;
  414. for( BOARD_ITEM* item = m_Track; item; item = item->Next() )
  415. {
  416. if( item->Type() == TYPE_VIA )
  417. viasCount++;
  418. }
  419. txt.Printf( wxT( "%d" ), GetPadsCount() );
  420. Affiche_1_Parametre( frame, POS_AFF_NBPADS, _( "Pads" ), txt, DARKGREEN );
  421. txt.Printf( wxT( "%d" ), viasCount );
  422. Affiche_1_Parametre( frame, POS_AFF_NBVIAS, _( "Vias" ), txt, DARKGREEN );
  423. txt.Printf( wxT( "%d" ), GetNodesCount() );
  424. Affiche_1_Parametre( frame, POS_AFF_NBNODES, _( "Nodes" ), txt, DARKCYAN );
  425. txt.Printf( wxT( "%d" ), m_NetInfo->GetNetsCount() );
  426. Affiche_1_Parametre( frame, POS_AFF_NBNETS, _( "Nets" ), txt, RED );
  427. /* These parameters are known only if the full ratsnest is available,
  428. * so, display them only if this is the case
  429. */
  430. if( (m_Status_Pcb & NET_CODES_OK) )
  431. {
  432. txt.Printf( wxT( "%d" ), GetRatsnestsCount() );
  433. Affiche_1_Parametre( frame, POS_AFF_NBLINKS, _( "Links" ), txt, DARKGREEN );
  434. txt.Printf( wxT( "%d" ), GetRatsnestsCount() - GetNoconnectCount() );
  435. Affiche_1_Parametre( frame, POS_AFF_NBCONNECT, _( "Connect" ), txt, DARKGREEN );
  436. txt.Printf( wxT( "%d" ), GetNoconnectCount() );
  437. Affiche_1_Parametre( frame, POS_AFF_NBNOCONNECT, _( "NoConn" ), txt, BLUE );
  438. }
  439. }
  440. // virtual, see pcbstruct.h
  441. SEARCH_RESULT BOARD::Visit( INSPECTOR* inspector, const void* testData,
  442. const KICAD_T scanTypes[] )
  443. {
  444. KICAD_T stype;
  445. SEARCH_RESULT result = SEARCH_CONTINUE;
  446. const KICAD_T* p = scanTypes;
  447. bool done = false;
  448. #if 0 && defined(DEBUG)
  449. std::cout << GetClass().mb_str() << ' ';
  450. #endif
  451. while( !done )
  452. {
  453. stype = *p;
  454. switch( stype )
  455. {
  456. case TYPE_PCB:
  457. result = inspector->Inspect( this, testData ); // inspect me
  458. // skip over any types handled in the above call.
  459. ++p;
  460. break;
  461. /* Instances of the requested KICAD_T live in a list, either one
  462. * that I manage, or that my modules manage. If it's a type managed
  463. * by class MODULE, then simply pass it on to each module's
  464. * MODULE::Visit() function by way of the
  465. * IterateForward( m_Modules, ... ) call.
  466. */
  467. case TYPE_MODULE:
  468. case TYPE_PAD:
  469. case TYPE_TEXTE_MODULE:
  470. case TYPE_EDGE_MODULE:
  471. // this calls MODULE::Visit() on each module.
  472. result = IterateForward( m_Modules, inspector, testData, p );
  473. // skip over any types handled in the above call.
  474. for( ; ; )
  475. {
  476. switch( stype = *++p )
  477. {
  478. case TYPE_MODULE:
  479. case TYPE_PAD:
  480. case TYPE_TEXTE_MODULE:
  481. case TYPE_EDGE_MODULE:
  482. continue;
  483. default:
  484. ;
  485. }
  486. break;
  487. }
  488. break;
  489. case TYPE_DRAWSEGMENT:
  490. case TYPE_TEXTE:
  491. case TYPE_COTATION:
  492. case TYPE_MIRE:
  493. result = IterateForward( m_Drawings, inspector, testData, p );
  494. // skip over any types handled in the above call.
  495. for( ; ; )
  496. {
  497. switch( stype = *++p )
  498. {
  499. case TYPE_DRAWSEGMENT:
  500. case TYPE_TEXTE:
  501. case TYPE_COTATION:
  502. case TYPE_MIRE:
  503. continue;
  504. default:
  505. ;
  506. }
  507. break;
  508. }
  509. ;
  510. break;
  511. #if 0 // both these are on same list, so we must scan it twice in order to get VIA priority,
  512. // using new #else code below.
  513. // But we are not using separte lists for TRACKs and SEGVIAs, because items are ordered (sortered) in the linked
  514. // list by netcode AND by physical distance:
  515. // when created, if a track or via is connected to an existing track or via, it is put in linked list
  516. // after this existing track or via
  517. // So usually, connected tracks or vias are grouped in this list
  518. // So the algorithm (used in rastnest computations) which computes the track connectivity is faster (more than 100 time regarding to
  519. // a non ordered list) because when it searchs for a connexion, first it tests the near (near in term of linked list) 50 items
  520. // from the current item (track or via) in test.
  521. // Usually, because of this sort, a connected item (if exists) is found.
  522. // If not found (and only in this case) an exhaustive (and time consumming) search is made,
  523. // but this case is statistically rare.
  524. case TYPE_VIA:
  525. case TYPE_TRACK:
  526. result = IterateForward( m_Track, inspector, testData, p );
  527. // skip over any types handled in the above call.
  528. for( ; ; )
  529. {
  530. switch( stype = *++p )
  531. {
  532. case TYPE_VIA:
  533. case TYPE_TRACK:
  534. continue;
  535. default:
  536. ;
  537. }
  538. break;
  539. }
  540. break;
  541. #else
  542. case TYPE_VIA:
  543. result = IterateForward( m_Track, inspector, testData, p );
  544. ++p;
  545. break;
  546. case TYPE_TRACK:
  547. result = IterateForward( m_Track, inspector, testData, p );
  548. ++p;
  549. break;
  550. #endif
  551. case TYPE_MARKER:
  552. // MARKERS are in the m_markers std::vector
  553. for( unsigned i = 0; i<m_markers.size(); ++i )
  554. {
  555. result = m_markers[i]->Visit( inspector, testData, p );
  556. if( result == SEARCH_QUIT )
  557. break;
  558. }
  559. ++p;
  560. break;
  561. case TYPE_ZONE_CONTAINER:
  562. // TYPE_ZONE_CONTAINER are in the m_ZoneDescriptorList std::vector
  563. for( unsigned i = 0; i< m_ZoneDescriptorList.size(); ++i )
  564. {
  565. result = m_ZoneDescriptorList[i]->Visit( inspector, testData, p );
  566. if( result == SEARCH_QUIT )
  567. break;
  568. }
  569. ++p;
  570. break;
  571. case TYPE_ZONE:
  572. result = IterateForward( m_Zone, inspector, testData, p );
  573. ++p;
  574. break;
  575. case TYPE_ZONE_UNUSED: // Unused type
  576. break;
  577. default: // catch EOT or ANY OTHER type here and return.
  578. done = true;
  579. break;
  580. }
  581. if( result == SEARCH_QUIT )
  582. break;
  583. }
  584. return result;
  585. }
  586. /* now using PcbGeneralLocateAndDisplay(), but this remains a useful example
  587. * of how the INSPECTOR can be used in a lightweight way.
  588. * // see pcbstruct.h
  589. * BOARD_ITEM* BOARD::FindPadOrModule( const wxPoint& refPos, int layer )
  590. * {
  591. * class PadOrModule : public INSPECTOR
  592. * {
  593. * public:
  594. * BOARD_ITEM* found;
  595. * int layer;
  596. * int layer_mask;
  597. *
  598. * PadOrModule( int alayer ) :
  599. * found(0), layer(alayer), layer_mask( g_TabOneLayerMask[alayer] )
  600. * {}
  601. *
  602. * SEARCH_RESULT Inspect( EDA_BaseStruct* testItem, const void* testData )
  603. * {
  604. * BOARD_ITEM* item = (BOARD_ITEM*) testItem;
  605. * const wxPoint& refPos = *(const wxPoint*) testData;
  606. *
  607. * if( item->Type() == TYPE_PAD )
  608. * {
  609. * D_PAD* pad = (D_PAD*) item;
  610. * if( pad->HitTest( refPos ) )
  611. * {
  612. * if( layer_mask & pad->m_Masque_Layer )
  613. * {
  614. * found = item;
  615. * return SEARCH_QUIT;
  616. * }
  617. * else if( !found )
  618. * {
  619. * MODULE* parent = (MODULE*) pad->m_Parent;
  620. * if( IsModuleLayerVisible( parent->GetLayer() ) )
  621. * found = item;
  622. * }
  623. * }
  624. * }
  625. *
  626. * else if( item->Type() == TYPE_MODULE )
  627. * {
  628. * MODULE* module = (MODULE*) item;
  629. *
  630. * // consider only visible modules
  631. * if( IsModuleLayerVisible( module->GetLayer() ) )
  632. * {
  633. * if( module->HitTest( refPos ) )
  634. * {
  635. * if( layer == module->GetLayer() )
  636. * {
  637. * found = item;
  638. * return SEARCH_QUIT;
  639. * }
  640. *
  641. * // layer mismatch, save in case we don't find a
  642. * // future layer match hit.
  643. * if( !found )
  644. * found = item;
  645. * }
  646. * }
  647. * }
  648. * return SEARCH_CONTINUE;
  649. * }
  650. * };
  651. *
  652. * PadOrModule inspector( layer );
  653. *
  654. * // search only for PADs first, then MODULES, and preferably a layer match
  655. * static const KICAD_T scanTypes[] = { TYPE_PAD, TYPE_MODULE, EOT };
  656. *
  657. * // visit this BOARD with the above inspector
  658. * Visit( &inspector, &refPos, scanTypes );
  659. *
  660. * return inspector.found;
  661. * }
  662. */
  663. /**
  664. * Function FindNet
  665. * searches for a net with the given netcode.
  666. * @param anetcode The netcode to search for.
  667. * @return EQUIPOT* - the net or NULL if not found.
  668. */
  669. NETINFO_ITEM* BOARD::FindNet( int anetcode ) const
  670. {
  671. // the first valid netcode is 1.
  672. // zero is reserved for "no connection" and is not used.
  673. if( anetcode > 0 )
  674. {
  675. wxASSERT( anetcode == m_NetInfo->GetNetItem( anetcode )->GetNet() );
  676. return m_NetInfo->GetNetItem( anetcode );
  677. }
  678. return NULL;
  679. }
  680. /**
  681. * Function FindNet overlayed
  682. * searches for a net with the given name.
  683. * @param aNetname A Netname to search for.
  684. * @return EQUIPOT* - the net or NULL if not found.
  685. */
  686. NETINFO_ITEM* BOARD::FindNet( const wxString& aNetname ) const
  687. {
  688. // the first valid netcode is 1.
  689. // zero is reserved for "no connection" and is not used.
  690. if( !aNetname.IsEmpty() )
  691. {
  692. for( unsigned ii = 1; ii < m_NetInfo->GetNetsCount(); ii++ )
  693. {
  694. if( m_NetInfo->GetNetItem( ii )->GetNetname() == aNetname )
  695. return m_NetInfo->GetNetItem( ii );
  696. }
  697. }
  698. return NULL;
  699. }
  700. MODULE* BOARD::FindModuleByReference( const wxString& aReference ) const
  701. {
  702. struct FindModule : public INSPECTOR
  703. {
  704. MODULE* found;
  705. FindModule() : found( 0 ) {}
  706. // implement interface INSPECTOR
  707. SEARCH_RESULT Inspect( EDA_BaseStruct* item, const void* data )
  708. {
  709. MODULE* module = (MODULE*) item;
  710. const wxString& ref = *(const wxString*) data;
  711. if( ref == module->GetReference() )
  712. {
  713. found = module;
  714. return SEARCH_QUIT;
  715. }
  716. return SEARCH_CONTINUE;
  717. }
  718. } inspector;
  719. // search only for MODULES
  720. static const KICAD_T scanTypes[] = { TYPE_MODULE, EOT };
  721. // visit this BOARD with the above inspector
  722. BOARD* nonconstMe = (BOARD*) this;
  723. nonconstMe->Visit( &inspector, &aReference, scanTypes );
  724. return inspector.found;
  725. }
  726. // Sort nets by decreasing pad count
  727. static bool s_SortByNodes( const NETINFO_ITEM* a, const NETINFO_ITEM* b )
  728. {
  729. return a->GetNodesCount() < b->GetNodesCount();
  730. }
  731. /**
  732. * Function ReturnSortedNetnamesList
  733. * @param aNames An array string to fill with net names.
  734. * @param aSortbyPadsCount : true = sort by active pads count, false = no sort (i.e. leave the sort by net names)
  735. * @return int - net names count.
  736. */
  737. int BOARD::ReturnSortedNetnamesList( wxArrayString& aNames, bool aSortbyPadsCount )
  738. {
  739. if( m_NetInfo->GetNetsCount() == 0 )
  740. return 0;
  741. /* Build the list */
  742. std::vector <NETINFO_ITEM*> netBuffer;
  743. netBuffer.reserve( m_NetInfo->GetNetsCount() );
  744. for( unsigned ii = 1; ii < m_NetInfo->GetNetsCount(); ii++ )
  745. {
  746. if( m_NetInfo->GetNetItem( ii )->GetNet() > 0 )
  747. netBuffer.push_back( m_NetInfo->GetNetItem( ii ) );
  748. }
  749. /* sort the list */
  750. if( aSortbyPadsCount )
  751. sort( netBuffer.begin(), netBuffer.end(), s_SortByNodes );
  752. for( unsigned ii = 0; ii < netBuffer.size(); ii++ )
  753. aNames.Add( netBuffer[ii]->GetNetname() );
  754. return netBuffer.size();
  755. }
  756. /************************************/
  757. bool BOARD::Save( FILE* aFile ) const
  758. /************************************/
  759. {
  760. bool rc = false;
  761. BOARD_ITEM* item;
  762. // save the nets
  763. for( unsigned ii = 0; ii < m_NetInfo->GetNetsCount(); ii++ )
  764. if( !m_NetInfo->GetNetItem( ii )->Save( aFile ) )
  765. goto out;
  766. // save the modules
  767. for( item = m_Modules; item; item = item->Next() )
  768. if( !item->Save( aFile ) )
  769. goto out;
  770. for( item = m_Drawings; item; item = item->Next() )
  771. {
  772. switch( item->Type() )
  773. {
  774. case TYPE_TEXTE:
  775. case TYPE_DRAWSEGMENT:
  776. case TYPE_MIRE:
  777. case TYPE_COTATION:
  778. if( !item->Save( aFile ) )
  779. goto out;
  780. break;
  781. default:
  782. // future: throw exception here
  783. #if defined(DEBUG)
  784. printf( "BOARD::Save() ignoring m_Drawings type %d\n", item->Type() );
  785. #endif
  786. break;
  787. }
  788. }
  789. // do not save MARKERs, they can be regenerated easily
  790. // save the tracks & vias
  791. fprintf( aFile, "$TRACK\n" );
  792. for( item = m_Track; item; item = item->Next() )
  793. if( !item->Save( aFile ) )
  794. goto out;
  795. fprintf( aFile, "$EndTRACK\n" );
  796. // save the zones
  797. fprintf( aFile, "$ZONE\n" );
  798. for( item = m_Zone; item; item = item->Next() )
  799. if( !item->Save( aFile ) )
  800. goto out;
  801. fprintf( aFile, "$EndZONE\n" );
  802. // save the zone edges
  803. for( unsigned ii = 0; ii < m_ZoneDescriptorList.size(); ii++ )
  804. {
  805. ZONE_CONTAINER* edge_zone = m_ZoneDescriptorList[ii];
  806. edge_zone->Save( aFile );
  807. }
  808. if( fprintf( aFile, "$EndBOARD\n" ) != sizeof("$EndBOARD\n") - 1 )
  809. goto out;
  810. rc = true; // wrote all OK
  811. out:
  812. return rc;
  813. }
  814. /***********************************************************************************************/
  815. void BOARD::RedrawAreasOutlines( WinEDA_DrawPanel* panel, wxDC* aDC, int aDrawMode, int aLayer )
  816. /***********************************************************************************************/
  817. /**
  818. * Function RedrawAreasOutlines
  819. * Redraw all areas outlines on layer aLayer ( redraw all if aLayer < 0 )
  820. */
  821. {
  822. if( !aDC )
  823. return;
  824. for( int ii = 0; ii < GetAreaCount(); ii++ )
  825. {
  826. ZONE_CONTAINER* edge_zone = GetArea( ii );
  827. if( (aLayer < 0) || ( aLayer == edge_zone->GetLayer() ) )
  828. edge_zone->Draw( panel, aDC, aDrawMode );
  829. }
  830. }
  831. /***********************************************************************************************/
  832. void BOARD::RedrawFilledAreas( WinEDA_DrawPanel* panel, wxDC* aDC, int aDrawMode, int aLayer )
  833. /***********************************************************************************************/
  834. /**
  835. * Function RedrawFilledAreas
  836. * Redraw all areas outlines on layer aLayer ( redraw all if aLayer < 0 )
  837. */
  838. {
  839. if( !aDC )
  840. return;
  841. for( int ii = 0; ii < GetAreaCount(); ii++ )
  842. {
  843. ZONE_CONTAINER* edge_zone = GetArea( ii );
  844. if( (aLayer < 0) || ( aLayer == edge_zone->GetLayer() ) )
  845. edge_zone->DrawFilledArea( panel, aDC, aDrawMode );
  846. }
  847. }
  848. /**
  849. * Function HitTestForAnyFilledArea
  850. * tests if the given wxPoint is within the bounds of a filled area of this zone.
  851. * the test is made on zones on layer from aStartLayer to aEndLayer
  852. * Note: if a zone has its flag BUSY (in .m_State) is set, it is ignored.
  853. * @param refPos A wxPoint to test
  854. * @param aStartLayer the first layer to test
  855. * @param aEndLayer the last layer (-1 to ignore it) to test
  856. * @return ZONE_CONTAINER* return a pointer to the ZONE_CONTAINER found, else NULL
  857. */
  858. ZONE_CONTAINER* BOARD::HitTestForAnyFilledArea( const wxPoint& aRefPos,
  859. int aStartLayer,
  860. int aEndLayer )
  861. {
  862. if( aEndLayer < 0 )
  863. aEndLayer = aStartLayer;
  864. if( aEndLayer < aStartLayer )
  865. EXCHG( aEndLayer, aStartLayer );
  866. for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ )
  867. {
  868. ZONE_CONTAINER* area = m_ZoneDescriptorList[ia];
  869. int layer = area->GetLayer();
  870. if( (layer < aStartLayer) || (layer > aEndLayer) )
  871. continue;
  872. if( area->GetState( BUSY ) ) // In locate functions we must skip tagged items with BUSY flag set.
  873. continue;
  874. if( area->HitTestFilledArea( aRefPos ) )
  875. return area;
  876. }
  877. return NULL;
  878. }
  879. /**
  880. * Function SetAreasNetCodesFromNetNames
  881. * Set the .m_NetCode member of all copper areas, according to the area Net Name
  882. * The SetNetCodesFromNetNames is an equivalent to net name, for fast comparisons.
  883. * However the Netcode is an arbitrary equivalence, it must be set after each netlist read
  884. * or net change
  885. * Must be called after pad netcodes are calculated
  886. * @return : error count
  887. * For non copper areas, netcode is set to 0
  888. */
  889. int BOARD::SetAreasNetCodesFromNetNames( void )
  890. {
  891. int error_count = 0;
  892. for( int ii = 0; ii < GetAreaCount(); ii++ )
  893. {
  894. if( !GetArea( ii )->IsOnCopperLayer() )
  895. {
  896. GetArea( ii )->SetNet( 0 );
  897. continue;
  898. }
  899. if( GetArea( ii )->GetNet() != 0 ) // i.e. if this zone is connected to a net
  900. {
  901. const NETINFO_ITEM* net = FindNet( GetArea( ii )->m_Netname );
  902. if( net )
  903. {
  904. GetArea( ii )->SetNet( net->GetNet() );
  905. }
  906. else
  907. {
  908. error_count++;
  909. GetArea( ii )->SetNet( -1 ); //keep Net Name ane set m_NetCode to -1 : error flag
  910. }
  911. }
  912. }
  913. return error_count;
  914. }
  915. #if defined(DEBUG)
  916. /**
  917. * Function Show
  918. * is used to output the object tree, currently for debugging only.
  919. * @param nestLevel An aid to prettier tree indenting, and is the level
  920. * of nesting of this object within the overall tree.
  921. * @param os The ostream& to output to.
  922. */
  923. void BOARD::Show( int nestLevel, std::ostream& os )
  924. {
  925. BOARD_ITEM* p;
  926. // for now, make it look like XML:
  927. NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() << ">\n";
  928. // specialization of the output:
  929. NestedSpace( nestLevel + 1, os ) << "<modules>\n";
  930. p = m_Modules;
  931. for( ; p; p = p->Next() )
  932. p->Show( nestLevel + 2, os );
  933. NestedSpace( nestLevel + 1, os ) << "</modules>\n";
  934. NestedSpace( nestLevel + 1, os ) << "<pdrawings>\n";
  935. p = m_Drawings;
  936. for( ; p; p = p->Next() )
  937. p->Show( nestLevel + 2, os );
  938. NestedSpace( nestLevel + 1, os ) << "</pdrawings>\n";
  939. NestedSpace( nestLevel + 1, os ) << "<tracks>\n";
  940. p = m_Track;
  941. for( ; p; p = p->Next() )
  942. p->Show( nestLevel + 2, os );
  943. NestedSpace( nestLevel + 1, os ) << "</tracks>\n";
  944. NestedSpace( nestLevel + 1, os ) << "<zones>\n";
  945. p = m_Zone;
  946. for( ; p; p = p->Next() )
  947. p->Show( nestLevel + 2, os );
  948. NestedSpace( nestLevel + 1, os ) << "</zones>\n";
  949. /*
  950. * NestedSpace( nestLevel+1, os ) << "<zone_container>\n";
  951. * for( ZONE_CONTAINERS::iterator i=m_ZoneDescriptorList.begin(); i!=m_ZoneDescriptorList.end(); ++i )
  952. * (*i)->Show( nestLevel+2, os );
  953. * NestedSpace( nestLevel+1, os ) << "</zone_container>\n";
  954. */
  955. p = (BOARD_ITEM*) m_Son;
  956. for( ; p; p = p->Next() )
  957. {
  958. p->Show( nestLevel + 1, os );
  959. }
  960. NestedSpace( nestLevel, os ) << "</" << GetClass().Lower().mb_str() << ">\n";
  961. }
  962. #endif