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.

1615 lines
45 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
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
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
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. #include "class_board_design_settings.h"
  8. #include "colors_selection.h"
  9. /* This is an odd place for this, but cvpcb won't link if it is
  10. * in class_board_item.cpp like I first tried it.
  11. */
  12. wxPoint BOARD_ITEM::ZeroOffset( 0, 0 );
  13. // Current design settings (used also to read configs):
  14. BOARD_DESIGN_SETTINGS boardDesignSettings;
  15. /*****************/
  16. /* Class BOARD: */
  17. /*****************/
  18. BOARD::BOARD( EDA_BaseStruct* parent, WinEDA_BasePcbFrame* frame ) :
  19. BOARD_ITEM( (BOARD_ITEM*)parent, TYPE_PCB ),
  20. m_NetClasses( this )
  21. {
  22. m_PcbFrame = frame;
  23. m_Status_Pcb = 0; // Status word: bit 1 = calculate.
  24. SetBoardDesignSettings(&boardDesignSettings);
  25. SetColorsSettings(&g_ColorsSettings);
  26. m_NbNodes = 0; // Number of connected pads.
  27. m_NbNoconnect = 0; // Number of unconnected nets.
  28. m_CurrentZoneContour = NULL; // This ZONE_CONTAINER handle the
  29. // zone contour currently in
  30. // progress
  31. m_NetInfo = new NETINFO_LIST( this ); // handle nets info list (name,
  32. // design constraints ..
  33. m_NetInfo->BuildListOfNets(); // prepare pads and nets lists
  34. // containers.
  35. for( int layer = 0; layer < NB_COPPER_LAYERS; ++layer )
  36. {
  37. m_Layer[layer].m_Name = GetDefaultLayerName( layer );
  38. m_Layer[layer].m_Type = LT_SIGNAL;
  39. }
  40. // Initial parameters for the default NETCLASS come from the global
  41. // preferences
  42. // within g_DesignSettings via the NETCLASS() constructor.
  43. // Should user eventually load a board from a disk file, then these
  44. // defaults
  45. // will get overwritten during load.
  46. m_NetClasses.GetDefault()->SetDescription(
  47. _( "This is the default net class." ) );
  48. m_ViaSizeSelector = 0;
  49. m_TrackWidthSelector = 0;
  50. // Initialize default values.
  51. SetCurrentNetClass( m_NetClasses.GetDefault()->GetName() );
  52. }
  53. BOARD::~BOARD()
  54. {
  55. if( m_PcbFrame->GetScreen() )
  56. m_PcbFrame->GetScreen()->ClearUndoRedoList();
  57. while( m_ZoneDescriptorList.size() )
  58. {
  59. ZONE_CONTAINER* area_to_remove = m_ZoneDescriptorList[0];
  60. Delete( area_to_remove );
  61. }
  62. m_FullRatsnest.clear();
  63. m_LocalRatsnest.clear();
  64. DeleteMARKERs();
  65. DeleteZONEOutlines();
  66. delete m_CurrentZoneContour;
  67. m_CurrentZoneContour = NULL;
  68. delete m_NetInfo;
  69. }
  70. /**
  71. * Function SetCurrentNetClass
  72. * Must be called after a netclass selection (or after a netclass parameter
  73. * change
  74. * Initialize vias and tracks values displayed in combo boxes of the auxiliary
  75. * toolbar and some other parameters (netclass name ....)
  76. * @param aNetClassName = the new netclass name
  77. * @return true if lists of tracks and vias sizes are modified
  78. */
  79. bool BOARD::SetCurrentNetClass( const wxString& aNetClassName )
  80. {
  81. NETCLASS* netClass = m_NetClasses.Find( aNetClassName );
  82. bool lists_sizes_modified = false;
  83. // if not found (should not happen) use the default
  84. if( netClass == NULL )
  85. netClass = m_NetClasses.GetDefault();
  86. m_CurrentNetClassName = netClass->GetName();
  87. // Initialize others values:
  88. if( m_ViasDimensionsList.size() == 0 )
  89. {
  90. VIA_DIMENSION viadim;
  91. lists_sizes_modified = true;
  92. m_ViasDimensionsList.push_back( viadim );
  93. }
  94. if( m_TrackWidthList.size() == 0 )
  95. {
  96. lists_sizes_modified = true;
  97. m_TrackWidthList.push_back( 0 );
  98. }
  99. /* note the m_ViasDimensionsList[0] and m_TrackWidthList[0] values
  100. * are always the Netclass values
  101. */
  102. if( m_ViasDimensionsList[0].m_Diameter != netClass->GetViaDiameter() )
  103. lists_sizes_modified = true;
  104. m_ViasDimensionsList[0].m_Diameter = netClass->GetViaDiameter();
  105. if( m_TrackWidthList[0] != netClass->GetTrackWidth() )
  106. lists_sizes_modified = true;
  107. m_TrackWidthList[0] = netClass->GetTrackWidth();
  108. if( m_ViaSizeSelector >= m_ViasDimensionsList.size() )
  109. m_ViaSizeSelector = m_ViasDimensionsList.size();
  110. if( m_TrackWidthSelector >= m_TrackWidthList.size() )
  111. m_TrackWidthSelector = m_TrackWidthList.size();
  112. return lists_sizes_modified;
  113. }
  114. /** function GetBiggestClearanceValue
  115. * @return the biggest clearance value found in NetClasses list
  116. */
  117. int BOARD::GetBiggestClearanceValue()
  118. {
  119. int clearance = m_NetClasses.GetDefault()->GetClearance();
  120. //Read list of Net Classes
  121. for( NETCLASSES::const_iterator nc = m_NetClasses.begin();
  122. nc != m_NetClasses.end();
  123. nc++ )
  124. {
  125. NETCLASS* netclass = nc->second;
  126. clearance = MAX( clearance, netclass->GetClearance() );
  127. }
  128. return clearance;
  129. }
  130. /** function GetCurrentMicroViaSize
  131. * @return the current micro via size,
  132. * that is the current netclass value
  133. */
  134. int BOARD::GetCurrentMicroViaSize()
  135. {
  136. NETCLASS* netclass = m_NetClasses.Find( m_CurrentNetClassName );
  137. return netclass->GetuViaDiameter();
  138. }
  139. /** function GetCurrentMicroViaDrill
  140. * @return the current micro via drill,
  141. * that is the current netclass value
  142. */
  143. int BOARD::GetCurrentMicroViaDrill()
  144. {
  145. NETCLASS* netclass = m_NetClasses.Find( m_CurrentNetClassName );
  146. return netclass->GetuViaDrill();
  147. }
  148. wxString BOARD::GetLayerName( int aLayerIndex ) const
  149. {
  150. if( !IsValidLayerIndex( aLayerIndex ) )
  151. return wxEmptyString;
  152. // copper layer names are stored in the BOARD.
  153. if( IsValidCopperLayerIndex( aLayerIndex ) && IsLayerEnabled( aLayerIndex ) )
  154. {
  155. // default names were set in BOARD::BOARD() but they may be
  156. // over-ridden by BOARD::SetLayerName()
  157. return m_Layer[aLayerIndex].m_Name;
  158. }
  159. return GetDefaultLayerName( aLayerIndex );
  160. }
  161. wxString BOARD::GetDefaultLayerName( int aLayerNumber )
  162. {
  163. const wxChar* txt;
  164. // These are only default layer names. For PCBNEW, the copper names
  165. // may be over-ridden in the BOARD (*.brd) file.
  166. // Use a switch to explicitly show the mapping more clearly
  167. switch( aLayerNumber )
  168. {
  169. case LAYER_N_FRONT: txt = _( "Front" ); break;
  170. case LAYER_N_2: txt = _( "Inner2" ); break;
  171. case LAYER_N_3: txt = _( "Inner3" ); break;
  172. case LAYER_N_4: txt = _( "Inner4" ); break;
  173. case LAYER_N_5: txt = _( "Inner5" ); break;
  174. case LAYER_N_6: txt = _( "Inner6" ); break;
  175. case LAYER_N_7: txt = _( "Inner7" ); break;
  176. case LAYER_N_8: txt = _( "Inner8" ); break;
  177. case LAYER_N_9: txt = _( "Inner9" ); break;
  178. case LAYER_N_10: txt = _( "Inner10" ); break;
  179. case LAYER_N_11: txt = _( "Inner11" ); break;
  180. case LAYER_N_12: txt = _( "Inner12" ); break;
  181. case LAYER_N_13: txt = _( "Inner13" ); break;
  182. case LAYER_N_14: txt = _( "Inner14" ); break;
  183. case LAYER_N_15: txt = _( "Inner15" ); break;
  184. case LAYER_N_BACK: txt = _( "Back" ); break;
  185. case ADHESIVE_N_BACK: txt = _( "Adhes_Back" ); break;
  186. case ADHESIVE_N_FRONT: txt = _( "Adhes_Front" ); break;
  187. case SOLDERPASTE_N_BACK: txt = _( "SoldP_Back" ); break;
  188. case SOLDERPASTE_N_FRONT: txt = _( "SoldP_Front" ); break;
  189. case SILKSCREEN_N_BACK: txt = _( "SilkS_Back" ); break;
  190. case SILKSCREEN_N_FRONT: txt = _( "SilkS_Front" ); break;
  191. case SOLDERMASK_N_BACK: txt = _( "Mask_Back" ); break;
  192. case SOLDERMASK_N_FRONT: txt = _( "Mask_Front" ); break;
  193. case DRAW_N: txt = _( "Drawings" ); break;
  194. case COMMENT_N: txt = _( "Comments" ); break;
  195. case ECO1_N: txt = _( "Eco1" ); break;
  196. case ECO2_N: txt = _( "Eco2" ); break;
  197. case EDGE_N: txt = _( "PCB_Edges" ); break;
  198. default: txt = _( "BAD INDEX" ); break;
  199. }
  200. return wxString( txt );
  201. }
  202. bool BOARD::SetLayerName( int aLayerIndex, const wxString& aLayerName )
  203. {
  204. if( !IsValidCopperLayerIndex( aLayerIndex ) )
  205. return false;
  206. if( aLayerName == wxEmptyString || aLayerName.Len() > 20 )
  207. return false;
  208. // no quote chars in the name allowed
  209. if( aLayerName.Find( wxChar( '"' ) ) != wxNOT_FOUND )
  210. return false;
  211. wxString NameTemp = aLayerName;
  212. // replace any spaces with underscores before we do any comparing
  213. NameTemp.Replace( wxT( " " ), wxT( "_" ) );
  214. if( IsLayerEnabled( aLayerIndex ) )
  215. {
  216. for( int i = 0; i < NB_COPPER_LAYERS; i++ )
  217. {
  218. if( i != aLayerIndex && IsLayerEnabled( i )
  219. && NameTemp == m_Layer[i].m_Name )
  220. return false;
  221. }
  222. m_Layer[aLayerIndex].m_Name = NameTemp;
  223. return true;
  224. }
  225. return false;
  226. }
  227. LAYER_T BOARD::GetLayerType( int aLayerIndex ) const
  228. {
  229. if( !IsValidCopperLayerIndex( aLayerIndex ) )
  230. return LT_SIGNAL;
  231. //@@IMB: The original test was broken due to the discontinuity
  232. // in the layer sequence.
  233. if( IsLayerEnabled( aLayerIndex ) )
  234. return m_Layer[aLayerIndex].m_Type;
  235. return LT_SIGNAL;
  236. }
  237. bool BOARD::SetLayerType( int aLayerIndex, LAYER_T aLayerType )
  238. {
  239. if( !IsValidCopperLayerIndex( aLayerIndex ) )
  240. return false;
  241. //@@IMB: The original test was broken due to the discontinuity
  242. // in the layer sequence.
  243. if( IsLayerEnabled( aLayerIndex ) )
  244. {
  245. m_Layer[aLayerIndex].m_Type = aLayerType;
  246. return true;
  247. }
  248. return false;
  249. }
  250. const char* LAYER::ShowType( LAYER_T aType )
  251. {
  252. const char* cp;
  253. switch( aType )
  254. {
  255. default:
  256. case LT_SIGNAL:
  257. cp = "signal";
  258. break;
  259. case LT_POWER:
  260. cp = "power";
  261. break;
  262. case LT_MIXED:
  263. cp = "mixed";
  264. break;
  265. case LT_JUMPER:
  266. cp = "jumper";
  267. break;
  268. }
  269. return cp;
  270. }
  271. LAYER_T LAYER::ParseType( const char* aType )
  272. {
  273. if( strcmp( aType, "signal" ) == 0 )
  274. return LT_SIGNAL;
  275. else if( strcmp( aType, "power" ) == 0 )
  276. return LT_POWER;
  277. else if( strcmp( aType, "mixed" ) == 0 )
  278. return LT_MIXED;
  279. else if( strcmp( aType, "jumper" ) == 0 )
  280. return LT_JUMPER;
  281. else
  282. return LAYER_T( -1 );
  283. }
  284. int BOARD::GetCopperLayerCount() const
  285. {
  286. return GetBoardDesignSettings()->GetCopperLayerCount();
  287. }
  288. void BOARD::SetCopperLayerCount( int aCount )
  289. {
  290. GetBoardDesignSettings()->SetCopperLayerCount( aCount );
  291. }
  292. int BOARD::GetEnabledLayers() const
  293. {
  294. return GetBoardDesignSettings()->GetEnabledLayers();
  295. }
  296. int BOARD::GetVisibleLayers() const
  297. {
  298. return GetBoardDesignSettings()->GetVisibleLayers();
  299. }
  300. void BOARD::SetEnabledLayers( int aLayerMask )
  301. {
  302. GetBoardDesignSettings()->SetEnabledLayers( aLayerMask );
  303. }
  304. void BOARD::SetVisibleLayers( int aLayerMask )
  305. {
  306. GetBoardDesignSettings()->SetVisibleLayers( aLayerMask );
  307. }
  308. // these are not tidy, since there are PCB_VISIBLEs that are not stored in the bitmap.
  309. void BOARD::SetVisibleElements( int aMask )
  310. {
  311. /* Call SetElementVisibility for each item,
  312. * to ensure specific calculations that can be needed by some items
  313. * just change the visibility flags could be not sufficient
  314. */
  315. for( int ii = 0; ii < PCB_VISIBLE(END_PCB_VISIBLE_LIST); ii++ )
  316. {
  317. int item_mask = 1 << ii;
  318. SetElementVisibility( ii, aMask & item_mask );
  319. }
  320. }
  321. // these are not tidy, since there are PCB_VISIBLEs that are not stored in the bitmap.
  322. void BOARD::SetVisibleAlls( )
  323. {
  324. SetVisibleLayers( FULL_LAYERS );
  325. /* Call SetElementVisibility for each item,
  326. * to ensure specific calculations that can be needed by some items
  327. */
  328. for( int ii = 0; ii < PCB_VISIBLE(END_PCB_VISIBLE_LIST); ii++ )
  329. SetElementVisibility( ii, true );
  330. }
  331. int BOARD::GetVisibleElements() const
  332. {
  333. return GetBoardDesignSettings()->GetVisibleElements();
  334. }
  335. bool BOARD::IsElementVisible( int aPCB_VISIBLE ) const
  336. {
  337. return GetBoardDesignSettings()->IsElementVisible( aPCB_VISIBLE );
  338. }
  339. void BOARD::SetElementVisibility( int aPCB_VISIBLE, bool isEnabled )
  340. {
  341. switch( aPCB_VISIBLE )
  342. {
  343. case RATSNEST_VISIBLE:
  344. GetBoardDesignSettings()->SetElementVisibility( aPCB_VISIBLE, isEnabled );
  345. // we must clear or set the CH_VISIBLE flags to hide/show ratsnet
  346. // because we have a tool to show hide ratsnest relative to a pad or a module
  347. // so the hide/show option is a per item selection
  348. if( IsElementVisible(RATSNEST_VISIBLE) )
  349. {
  350. for( unsigned ii = 0; ii < GetRatsnestsCount(); ii++ )
  351. m_FullRatsnest[ii].m_Status |= CH_VISIBLE;
  352. }
  353. else
  354. {
  355. for( unsigned ii = 0; ii < GetRatsnestsCount(); ii++ )
  356. m_FullRatsnest[ii].m_Status &= ~CH_VISIBLE;
  357. }
  358. break;
  359. default:
  360. GetBoardDesignSettings()->SetElementVisibility( aPCB_VISIBLE, isEnabled );
  361. }
  362. }
  363. int BOARD::GetVisibleElementColor( int aPCB_VISIBLE )
  364. {
  365. int color = -1;
  366. switch( aPCB_VISIBLE )
  367. {
  368. case VIA_THROUGH_VISIBLE:
  369. case VIA_MICROVIA_VISIBLE:
  370. case VIA_BBLIND_VISIBLE:
  371. case MOD_TEXT_FR_VISIBLE:
  372. case MOD_TEXT_BK_VISIBLE:
  373. case MOD_TEXT_INVISIBLE:
  374. case ANCHOR_VISIBLE:
  375. case PAD_FR_VISIBLE:
  376. case PAD_BK_VISIBLE:
  377. case RATSNEST_VISIBLE:
  378. case GRID_VISIBLE:
  379. color = GetColorsSettings()->GetItemColor( aPCB_VISIBLE );
  380. break;
  381. default:
  382. wxLogDebug( wxT( "BOARD::GetVisibleElementColor(): bad arg %d" ), aPCB_VISIBLE );
  383. }
  384. return color;
  385. }
  386. void BOARD::SetVisibleElementColor( int aPCB_VISIBLE, int aColor )
  387. {
  388. switch( aPCB_VISIBLE )
  389. {
  390. case VIA_THROUGH_VISIBLE:
  391. case VIA_MICROVIA_VISIBLE:
  392. case VIA_BBLIND_VISIBLE:
  393. case MOD_TEXT_FR_VISIBLE:
  394. case MOD_TEXT_BK_VISIBLE:
  395. case MOD_TEXT_INVISIBLE:
  396. case ANCHOR_VISIBLE:
  397. case PAD_FR_VISIBLE:
  398. case PAD_BK_VISIBLE:
  399. case GRID_VISIBLE:
  400. case RATSNEST_VISIBLE:
  401. GetColorsSettings()->SetItemColor( aPCB_VISIBLE, aColor );
  402. break;
  403. default:
  404. wxLogDebug( wxT( "BOARD::SetVisibleElementColor(): bad arg %d" ), aPCB_VISIBLE );
  405. }
  406. }
  407. void BOARD::SetLayerColor( int aLayer, int aColor )
  408. {
  409. GetColorsSettings()->SetLayerColor( aLayer, aColor );
  410. }
  411. int BOARD::GetLayerColor( int aLayer )
  412. {
  413. return GetColorsSettings()->GetLayerColor( aLayer );
  414. }
  415. /**
  416. * Function IsModuleLayerVisible
  417. * expects either of the two layers on which a module can reside, and returns
  418. * whether that layer is visible.
  419. * @param layer One of the two allowed layers for modules: LAYER_N_FRONT or LAYER_N_BACK
  420. * @return bool - true if the layer is visible, else false.
  421. */
  422. bool BOARD::IsModuleLayerVisible( int layer )
  423. {
  424. if( layer==LAYER_N_FRONT )
  425. return IsElementVisible( PCB_VISIBLE(MOD_FR_VISIBLE) );
  426. else if( layer==LAYER_N_BACK )
  427. return IsElementVisible( PCB_VISIBLE(MOD_BK_VISIBLE) );
  428. else
  429. return true;
  430. }
  431. wxPoint& BOARD::GetPosition()
  432. {
  433. static wxPoint dummy( 0, 0 );
  434. return dummy; // a reference
  435. }
  436. void BOARD::Add( BOARD_ITEM* aBoardItem, int aControl )
  437. {
  438. if( aBoardItem == NULL )
  439. {
  440. wxFAIL_MSG( wxT( "BOARD::Add() param error: aBoardItem NULL" ) );
  441. return;
  442. }
  443. switch( aBoardItem->Type() )
  444. {
  445. // this one uses a vector
  446. case TYPE_MARKER_PCB:
  447. aBoardItem->SetParent( this );
  448. m_markers.push_back( (MARKER_PCB*) aBoardItem );
  449. break;
  450. // this one uses a vector
  451. case TYPE_ZONE_CONTAINER:
  452. aBoardItem->SetParent( this );
  453. m_ZoneDescriptorList.push_back( (ZONE_CONTAINER*) aBoardItem );
  454. break;
  455. case TYPE_TRACK:
  456. case TYPE_VIA:
  457. {
  458. TRACK* insertAid = ( (TRACK*) aBoardItem )->GetBestInsertPoint( this );
  459. m_Track.Insert( (TRACK*) aBoardItem, insertAid );
  460. }
  461. break;
  462. case TYPE_ZONE:
  463. if( aControl & ADD_APPEND )
  464. m_Zone.PushBack( (SEGZONE*) aBoardItem );
  465. else
  466. m_Zone.PushFront( (SEGZONE*) aBoardItem );
  467. aBoardItem->SetParent( this );
  468. break;
  469. case TYPE_MODULE:
  470. if( aControl & ADD_APPEND )
  471. m_Modules.PushBack( (MODULE*) aBoardItem );
  472. else
  473. m_Modules.PushFront( (MODULE*) aBoardItem );
  474. aBoardItem->SetParent( this );
  475. // Because the list of pads has changed, reset the status
  476. // This indicate the list of pad and nets must be recalculated before
  477. // use
  478. m_Status_Pcb = 0;
  479. break;
  480. case TYPE_DIMENSION:
  481. case TYPE_DRAWSEGMENT:
  482. case TYPE_TEXTE:
  483. case TYPE_EDGE_MODULE:
  484. case TYPE_MIRE:
  485. if( aControl & ADD_APPEND )
  486. m_Drawings.PushBack( aBoardItem );
  487. else
  488. m_Drawings.PushFront( aBoardItem );
  489. aBoardItem->SetParent( this );
  490. break;
  491. // other types may use linked list
  492. default:
  493. {
  494. wxString msg;
  495. msg.Printf(
  496. wxT( "BOARD::Add() needs work: BOARD_ITEM type (%d) not handled" ),
  497. aBoardItem->Type() );
  498. wxFAIL_MSG( msg );
  499. }
  500. break;
  501. }
  502. }
  503. BOARD_ITEM* BOARD::Remove( BOARD_ITEM* aBoardItem )
  504. {
  505. // find these calls and fix them! Don't send me no stinkin' NULL.
  506. wxASSERT( aBoardItem );
  507. switch( aBoardItem->Type() )
  508. {
  509. case TYPE_MARKER_PCB:
  510. // find the item in the vector, then remove it
  511. for( unsigned i = 0; i<m_markers.size(); ++i )
  512. {
  513. if( m_markers[i] == (MARKER_PCB*) aBoardItem )
  514. {
  515. m_markers.erase( m_markers.begin() + i );
  516. break;
  517. }
  518. }
  519. break;
  520. case TYPE_ZONE_CONTAINER: // this one uses a vector
  521. // find the item in the vector, then delete then erase it.
  522. for( unsigned i = 0; i<m_ZoneDescriptorList.size(); ++i )
  523. {
  524. if( m_ZoneDescriptorList[i] == (ZONE_CONTAINER*) aBoardItem )
  525. {
  526. m_ZoneDescriptorList.erase( m_ZoneDescriptorList.begin() + i );
  527. break;
  528. }
  529. }
  530. break;
  531. case TYPE_MODULE:
  532. m_Modules.Remove( (MODULE*) aBoardItem );
  533. break;
  534. case TYPE_TRACK:
  535. case TYPE_VIA:
  536. m_Track.Remove( (TRACK*) aBoardItem );
  537. break;
  538. case TYPE_ZONE:
  539. m_Zone.Remove( (SEGZONE*) aBoardItem );
  540. break;
  541. case TYPE_DIMENSION:
  542. case TYPE_DRAWSEGMENT:
  543. case TYPE_TEXTE:
  544. case TYPE_EDGE_MODULE:
  545. case TYPE_MIRE:
  546. m_Drawings.Remove( aBoardItem );
  547. break;
  548. // other types may use linked list
  549. default:
  550. wxFAIL_MSG( wxT( "BOARD::Remove() needs more ::Type() support" ) );
  551. }
  552. return aBoardItem;
  553. }
  554. void BOARD::DeleteMARKERs()
  555. {
  556. // the vector does not know how to delete the MARKER_PCB, it holds pointers
  557. for( unsigned i = 0; i<m_markers.size(); ++i )
  558. delete m_markers[i];
  559. m_markers.clear();
  560. }
  561. void BOARD::DeleteZONEOutlines()
  562. {
  563. // the vector does not know how to delete the ZONE Outlines, it holds
  564. // pointers
  565. for( unsigned i = 0; i<m_ZoneDescriptorList.size(); ++i )
  566. delete m_ZoneDescriptorList[i];
  567. m_ZoneDescriptorList.clear();
  568. }
  569. /* Calculate the track segment count */
  570. int BOARD::GetNumSegmTrack()
  571. {
  572. return m_Track.GetCount();
  573. }
  574. /* Calculate the zone segment count */
  575. int BOARD::GetNumSegmZone()
  576. {
  577. return m_Zone.GetCount();
  578. }
  579. // return the unconnection count
  580. unsigned BOARD::GetNoconnectCount()
  581. {
  582. return m_NbNoconnect;
  583. }
  584. // return the active pad count ( pads with a netcode > 0 )
  585. unsigned BOARD::GetNodesCount()
  586. {
  587. return m_NbNodes;
  588. }
  589. /** Function ComputeBoundaryBox()
  590. * Calculate the bounding box of the board
  591. * This box contains pcb edges, pads , vias and tracks
  592. * Update m_PcbBox member
  593. *
  594. * @return 0 for an empty board (no items), else 1
  595. */
  596. bool BOARD::ComputeBoundaryBox()
  597. {
  598. int rayon, cx, cy, d, xmin, ymin, xmax, ymax;
  599. bool hasItems = FALSE;
  600. EDA_BaseStruct* PtStruct;
  601. DRAWSEGMENT* ptr;
  602. xmin = ymin = 0x7FFFFFFFl;
  603. xmax = ymax = -0x7FFFFFFFl;
  604. /* Analyze PCB edges*/
  605. PtStruct = m_Drawings;
  606. for( ; PtStruct != NULL; PtStruct = PtStruct->Next() )
  607. {
  608. if( PtStruct->Type() != TYPE_DRAWSEGMENT )
  609. continue;
  610. ptr = (DRAWSEGMENT*) PtStruct;
  611. d = (ptr->m_Width / 2) + 1;
  612. if( ptr->m_Shape == S_CIRCLE )
  613. {
  614. cx = ptr->m_Start.x; cy = ptr->m_Start.y;
  615. rayon = (int) hypot( (double) ( ptr->m_End.x - cx ),
  616. (double) ( ptr->m_End.y - cy ) );
  617. rayon += d;
  618. xmin = MIN( xmin, cx - rayon );
  619. ymin = MIN( ymin, cy - rayon );
  620. xmax = MAX( xmax, cx + rayon );
  621. ymax = MAX( ymax, cy + rayon );
  622. hasItems = TRUE;
  623. }
  624. else
  625. {
  626. cx = MIN( ptr->m_Start.x, ptr->m_End.x );
  627. cy = MIN( ptr->m_Start.y, ptr->m_End.y );
  628. xmin = MIN( xmin, cx - d );
  629. ymin = MIN( ymin, cy - d );
  630. cx = MAX( ptr->m_Start.x, ptr->m_End.x );
  631. cy = MAX( ptr->m_Start.y, ptr->m_End.y );
  632. xmax = MAX( xmax, cx + d );
  633. ymax = MAX( ymax, cy + d );
  634. hasItems = TRUE;
  635. }
  636. }
  637. /* Analyze footprints */
  638. for( MODULE* module = m_Modules; module; module = module->Next() )
  639. {
  640. hasItems = TRUE;
  641. EDA_Rect box = module->GetBoundingBox();
  642. xmin = MIN( xmin, box.GetX() );
  643. ymin = MIN( ymin, box.GetY() );
  644. xmax = MAX( xmax, box.GetRight() );
  645. ymax = MAX( ymax, box.GetBottom() );
  646. }
  647. /* Analize track and zones */
  648. for( TRACK* track = m_Track; track; track = track->Next() )
  649. {
  650. d = ( track->m_Width / 2 ) + 1;
  651. cx = MIN( track->m_Start.x, track->m_End.x );
  652. cy = MIN( track->m_Start.y, track->m_End.y );
  653. xmin = MIN( xmin, cx - d );
  654. ymin = MIN( ymin, cy - d );
  655. cx = MAX( track->m_Start.x, track->m_End.x );
  656. cy = MAX( track->m_Start.y, track->m_End.y );
  657. xmax = MAX( xmax, cx + d );
  658. ymax = MAX( ymax, cy + d );
  659. hasItems = TRUE;
  660. }
  661. for( TRACK* track = m_Zone; track; track = track->Next() )
  662. {
  663. d = ( track->m_Width / 2 ) + 1;
  664. cx = MIN( track->m_Start.x, track->m_End.x );
  665. cy = MIN( track->m_Start.y, track->m_End.y );
  666. xmin = MIN( xmin, cx - d );
  667. ymin = MIN( ymin, cy - d );
  668. cx = MAX( track->m_Start.x, track->m_End.x );
  669. cy = MAX( track->m_Start.y, track->m_End.y );
  670. xmax = MAX( xmax, cx + d );
  671. ymax = MAX( ymax, cy + d );
  672. hasItems = TRUE;
  673. }
  674. if( !hasItems && m_PcbFrame )
  675. {
  676. if( m_PcbFrame->m_Draw_Sheet_Ref )
  677. {
  678. xmin = ymin = 0;
  679. xmax = m_PcbFrame->GetScreen()->ReturnPageSize().x;
  680. ymax = m_PcbFrame->GetScreen()->ReturnPageSize().y;
  681. }
  682. else
  683. {
  684. xmin = -m_PcbFrame->GetScreen()->ReturnPageSize().x / 2;
  685. ymin = -m_PcbFrame->GetScreen()->ReturnPageSize().y / 2;
  686. xmax = m_PcbFrame->GetScreen()->ReturnPageSize().x / 2;
  687. ymax = m_PcbFrame->GetScreen()->ReturnPageSize().y / 2;
  688. }
  689. }
  690. m_BoundaryBox.SetX( xmin );
  691. m_BoundaryBox.SetY( ymin );
  692. m_BoundaryBox.SetWidth( xmax - xmin );
  693. m_BoundaryBox.SetHeight( ymax - ymin );
  694. return hasItems;
  695. }
  696. // virtual, see pcbstruct.h
  697. /* Display board statistics: pads, nets, connections.. count
  698. */
  699. void BOARD::DisplayInfo( WinEDA_DrawFrame* frame )
  700. {
  701. wxString txt;
  702. frame->ClearMsgPanel();
  703. int viasCount = 0;
  704. for( BOARD_ITEM* item = m_Track; item; item = item->Next() )
  705. {
  706. if( item->Type() == TYPE_VIA )
  707. viasCount++;
  708. }
  709. txt.Printf( wxT( "%d" ), GetPadsCount() );
  710. frame->AppendMsgPanel( _( "Pads" ), txt, DARKGREEN );
  711. txt.Printf( wxT( "%d" ), viasCount );
  712. frame->AppendMsgPanel( _( "Vias" ), txt, DARKGREEN );
  713. txt.Printf( wxT( "%d" ), GetNodesCount() );
  714. frame->AppendMsgPanel( _( "Nodes" ), txt, DARKCYAN );
  715. txt.Printf( wxT( "%d" ), m_NetInfo->GetCount() );
  716. frame->AppendMsgPanel( _( "Nets" ), txt, RED );
  717. /* These parameters are known only if the full ratsnest is available,
  718. * so, display them only if this is the case
  719. */
  720. if( (m_Status_Pcb & NET_CODES_OK) )
  721. {
  722. txt.Printf( wxT( "%d" ), GetRatsnestsCount() );
  723. frame->AppendMsgPanel( _( "Links" ), txt, DARKGREEN );
  724. txt.Printf( wxT( "%d" ), GetRatsnestsCount() - GetNoconnectCount() );
  725. frame->AppendMsgPanel( _( "Connect" ), txt, DARKGREEN );
  726. txt.Printf( wxT( "%d" ), GetNoconnectCount() );
  727. frame->AppendMsgPanel( _( "Unconnected" ), txt, BLUE );
  728. }
  729. }
  730. // virtual, see pcbstruct.h
  731. SEARCH_RESULT BOARD::Visit( INSPECTOR* inspector, const void* testData,
  732. const KICAD_T scanTypes[] )
  733. {
  734. KICAD_T stype;
  735. SEARCH_RESULT result = SEARCH_CONTINUE;
  736. const KICAD_T* p = scanTypes;
  737. bool done = false;
  738. #if 0 && defined(DEBUG)
  739. std::cout << GetClass().mb_str() << ' ';
  740. #endif
  741. while( !done )
  742. {
  743. stype = *p;
  744. switch( stype )
  745. {
  746. case TYPE_PCB:
  747. result = inspector->Inspect( this, testData ); // inspect me
  748. // skip over any types handled in the above call.
  749. ++p;
  750. break;
  751. /* Instances of the requested KICAD_T live in a list, either one
  752. * that I manage, or that my modules manage. If it's a type managed
  753. * by class MODULE, then simply pass it on to each module's
  754. * MODULE::Visit() function by way of the
  755. * IterateForward( m_Modules, ... ) call.
  756. */
  757. case TYPE_MODULE:
  758. case TYPE_PAD:
  759. case TYPE_TEXTE_MODULE:
  760. case TYPE_EDGE_MODULE:
  761. // this calls MODULE::Visit() on each module.
  762. result = IterateForward( m_Modules, inspector, testData, p );
  763. // skip over any types handled in the above call.
  764. for( ; ; )
  765. {
  766. switch( stype = *++p )
  767. {
  768. case TYPE_MODULE:
  769. case TYPE_PAD:
  770. case TYPE_TEXTE_MODULE:
  771. case TYPE_EDGE_MODULE:
  772. continue;
  773. default:
  774. ;
  775. }
  776. break;
  777. }
  778. break;
  779. case TYPE_DRAWSEGMENT:
  780. case TYPE_TEXTE:
  781. case TYPE_DIMENSION:
  782. case TYPE_MIRE:
  783. result = IterateForward( m_Drawings, inspector, testData, p );
  784. // skip over any types handled in the above call.
  785. for( ; ; )
  786. {
  787. switch( stype = *++p )
  788. {
  789. case TYPE_DRAWSEGMENT:
  790. case TYPE_TEXTE:
  791. case TYPE_DIMENSION:
  792. case TYPE_MIRE:
  793. continue;
  794. default:
  795. ;
  796. }
  797. break;
  798. }
  799. ;
  800. break;
  801. #if 0 // both these are on same list, so we must scan it twice in order
  802. // to get VIA priority, using new #else code below.
  803. // But we are not using separate lists for TRACKs and SEGVIAs, because
  804. // items are ordered (sorted) in the linked
  805. // list by netcode AND by physical distance:
  806. // when created, if a track or via is connected to an existing track or
  807. // via, it is put in linked list after this existing track or via
  808. // So usually, connected tracks or vias are grouped in this list
  809. // So the algorithm (used in rastnest computations) which computes the
  810. // track connectivity is faster (more than 100 time regarding to
  811. // a non ordered list) because when it searches for a connexion, first
  812. // it tests the near (near in term of linked list) 50 items
  813. // from the current item (track or via) in test.
  814. // Usually, because of this sort, a connected item (if exists) is
  815. // found.
  816. // If not found (and only in this case) an exhaustive (and time
  817. // consuming) search is made, but this case is statistically rare.
  818. case TYPE_VIA:
  819. case TYPE_TRACK:
  820. result = IterateForward( m_Track, inspector, testData, p );
  821. // skip over any types handled in the above call.
  822. for( ; ; )
  823. {
  824. switch( stype = *++p )
  825. {
  826. case TYPE_VIA:
  827. case TYPE_TRACK:
  828. continue;
  829. default:
  830. ;
  831. }
  832. break;
  833. }
  834. break;
  835. #else
  836. case TYPE_VIA:
  837. result = IterateForward( m_Track, inspector, testData, p );
  838. ++p;
  839. break;
  840. case TYPE_TRACK:
  841. result = IterateForward( m_Track, inspector, testData, p );
  842. ++p;
  843. break;
  844. #endif
  845. case TYPE_MARKER_PCB:
  846. // MARKER_PCBS are in the m_markers std::vector
  847. for( unsigned i = 0; i<m_markers.size(); ++i )
  848. {
  849. result = m_markers[i]->Visit( inspector, testData, p );
  850. if( result == SEARCH_QUIT )
  851. break;
  852. }
  853. ++p;
  854. break;
  855. case TYPE_ZONE_CONTAINER:
  856. // TYPE_ZONE_CONTAINER are in the m_ZoneDescriptorList std::vector
  857. for( unsigned i = 0; i< m_ZoneDescriptorList.size(); ++i )
  858. {
  859. result = m_ZoneDescriptorList[i]->Visit( inspector,
  860. testData,
  861. p );
  862. if( result == SEARCH_QUIT )
  863. break;
  864. }
  865. ++p;
  866. break;
  867. case TYPE_ZONE:
  868. result = IterateForward( m_Zone, inspector, testData, p );
  869. ++p;
  870. break;
  871. default: // catch EOT or ANY OTHER type here and return.
  872. done = true;
  873. break;
  874. }
  875. if( result == SEARCH_QUIT )
  876. break;
  877. }
  878. return result;
  879. }
  880. /* now using PcbGeneralLocateAndDisplay(), but this remains a useful example
  881. * of how the INSPECTOR can be used in a lightweight way.
  882. * // see pcbstruct.h
  883. * BOARD_ITEM* BOARD::FindPadOrModule( const wxPoint& refPos, int layer )
  884. * {
  885. * class PadOrModule : public INSPECTOR
  886. * {
  887. * public:
  888. * BOARD_ITEM* found;
  889. * int layer;
  890. * int layer_mask;
  891. *
  892. * PadOrModule( int alayer ) :
  893. * found(0), layer(alayer), layer_mask( g_TabOneLayerMask[alayer] )
  894. * {}
  895. *
  896. * SEARCH_RESULT Inspect( EDA_BaseStruct* testItem, const void* testData
  897. * )
  898. * {
  899. * BOARD_ITEM* item = (BOARD_ITEM*) testItem;
  900. * const wxPoint& refPos = *(const wxPoint*) testData;
  901. *
  902. * if( item->Type() == TYPE_PAD )
  903. * {
  904. * D_PAD* pad = (D_PAD*) item;
  905. * if( pad->HitTest( refPos ) )
  906. * {
  907. * if( layer_mask & pad->m_Masque_Layer )
  908. * {
  909. * found = item;
  910. * return SEARCH_QUIT;
  911. * }
  912. * else if( !found )
  913. * {
  914. * MODULE* parent = (MODULE*) pad->m_Parent;
  915. * if( IsModuleLayerVisible( parent->GetLayer() ) )
  916. * found = item;
  917. * }
  918. * }
  919. * }
  920. *
  921. * else if( item->Type() == TYPE_MODULE )
  922. * {
  923. * MODULE* module = (MODULE*) item;
  924. *
  925. * // consider only visible modules
  926. * if( IsModuleLayerVisible( module->GetLayer() ) )
  927. * {
  928. * if( module->HitTest( refPos ) )
  929. * {
  930. * if( layer == module->GetLayer() )
  931. * {
  932. * found = item;
  933. * return SEARCH_QUIT;
  934. * }
  935. *
  936. * // layer mismatch, save in case we don't find a
  937. * // future layer match hit.
  938. * if( !found )
  939. * found = item;
  940. * }
  941. * }
  942. * }
  943. * return SEARCH_CONTINUE;
  944. * }
  945. * };
  946. *
  947. * PadOrModule inspector( layer );
  948. *
  949. * // search only for PADs first, then MODULES, and preferably a layer match
  950. * static const KICAD_T scanTypes[] = { TYPE_PAD, TYPE_MODULE, EOT };
  951. *
  952. * // visit this BOARD with the above inspector
  953. * Visit( &inspector, &refPos, scanTypes );
  954. *
  955. * return inspector.found;
  956. * }
  957. */
  958. /**
  959. * Function FindNet
  960. * searches for a net with the given netcode.
  961. * @param anetcode The netcode to search for.
  962. * @return NETINFO_ITEM* - the net or NULL if not found.
  963. */
  964. NETINFO_ITEM* BOARD::FindNet( int anetcode ) const
  965. {
  966. // the first valid netcode is 1 and the last is m_NetInfo->GetCount()-1.
  967. // zero is reserved for "no connection" and is not used.
  968. // NULL is returned for non valid netcodes
  969. NETINFO_ITEM* net = m_NetInfo->GetNetItem( anetcode );
  970. #if defined(DEBUG)
  971. if( net ) // item can be NULL if anetcode is not valid
  972. {
  973. if( anetcode != net->GetNet() )
  974. {
  975. printf( "FindNet() anetcode %d != GetNet() %d (net: %s)\n",
  976. anetcode, net->GetNet(), CONV_TO_UTF8( net->GetNetname() ) );
  977. }
  978. }
  979. #endif
  980. return net;
  981. }
  982. /**
  983. * Function FindNet overlaid
  984. * searches for a net with the given name.
  985. * @param aNetname A Netname to search for.
  986. * @return NETINFO_ITEM* - the net or NULL if not found.
  987. */
  988. NETINFO_ITEM* BOARD::FindNet( const wxString& aNetname ) const
  989. {
  990. // the first valid netcode is 1.
  991. // zero is reserved for "no connection" and is not used.
  992. if( aNetname.IsEmpty() )
  993. return NULL;
  994. int ncount = m_NetInfo->GetCount();
  995. // Search for a netname = aNetname
  996. #if 0
  997. // Use a sequential search: easy to understand, but slow
  998. for( int ii = 1; ii < ncount; ii++ )
  999. {
  1000. NETINFO_ITEM* item = m_NetInfo->GetNetItem( ii );
  1001. if( item && item->GetNetname() == aNetname )
  1002. {
  1003. return item;
  1004. }
  1005. }
  1006. #else
  1007. // Use a fast binary search,
  1008. // this is possible because Nets are alphabetically ordered in list
  1009. // see NETINFO_LIST::BuildListOfNets() and
  1010. // NETINFO_LIST::Build_Pads_Full_List()
  1011. int imax = ncount - 1;
  1012. int index = imax;
  1013. while( ncount > 0 )
  1014. {
  1015. int ii = ncount;
  1016. ncount >>= 1;
  1017. if( (ii & 1) && ( ii > 1 ) )
  1018. ncount++;
  1019. NETINFO_ITEM* item = m_NetInfo->GetNetItem( index );
  1020. if( item == NULL )
  1021. return NULL;
  1022. int icmp = item->GetNetname().Cmp( aNetname );
  1023. if( icmp == 0 ) // found !
  1024. {
  1025. return item;
  1026. }
  1027. if( icmp < 0 ) // must search after item
  1028. {
  1029. index += ncount;
  1030. if( index > imax )
  1031. index = imax;
  1032. continue;
  1033. }
  1034. if( icmp > 0 ) // must search before item
  1035. {
  1036. index -= ncount;
  1037. if( index < 1 )
  1038. index = 1;
  1039. continue;
  1040. }
  1041. }
  1042. #endif
  1043. return NULL;
  1044. }
  1045. MODULE* BOARD::FindModuleByReference( const wxString& aReference ) const
  1046. {
  1047. struct FindModule : public INSPECTOR
  1048. {
  1049. MODULE* found;
  1050. FindModule() : found( 0 ) {}
  1051. // implement interface INSPECTOR
  1052. SEARCH_RESULT Inspect( EDA_BaseStruct* item, const void* data )
  1053. {
  1054. MODULE* module = (MODULE*) item;
  1055. const wxString& ref = *(const wxString*) data;
  1056. if( ref == module->GetReference() )
  1057. {
  1058. found = module;
  1059. return SEARCH_QUIT;
  1060. }
  1061. return SEARCH_CONTINUE;
  1062. }
  1063. } inspector;
  1064. // search only for MODULES
  1065. static const KICAD_T scanTypes[] = { TYPE_MODULE, EOT };
  1066. // visit this BOARD with the above inspector
  1067. BOARD* nonconstMe = (BOARD*) this;
  1068. nonconstMe->Visit( &inspector, &aReference, scanTypes );
  1069. return inspector.found;
  1070. }
  1071. // Sort nets by decreasing pad count
  1072. static bool s_SortByNodes( const NETINFO_ITEM* a, const NETINFO_ITEM* b )
  1073. {
  1074. return b->GetNodesCount() < a->GetNodesCount();
  1075. }
  1076. /**
  1077. * Function ReturnSortedNetnamesList
  1078. * @param aNames An array string to fill with net names.
  1079. * @param aSortbyPadsCount : true = sort by active pads count, false = no sort
  1080. * (i.e. leave the sort by net names)
  1081. * @return int - net names count.
  1082. */
  1083. int BOARD::ReturnSortedNetnamesList( wxArrayString& aNames,
  1084. bool aSortbyPadsCount )
  1085. {
  1086. if( m_NetInfo->GetCount() == 0 )
  1087. return 0;
  1088. // Build the list
  1089. std::vector <NETINFO_ITEM*> netBuffer;
  1090. netBuffer.reserve( m_NetInfo->GetCount() );
  1091. for( unsigned ii = 1; ii < m_NetInfo->GetCount(); ii++ )
  1092. {
  1093. if( m_NetInfo->GetNetItem( ii )->GetNet() > 0 )
  1094. netBuffer.push_back( m_NetInfo->GetNetItem( ii ) );
  1095. }
  1096. // sort the list
  1097. if( aSortbyPadsCount )
  1098. sort( netBuffer.begin(), netBuffer.end(), s_SortByNodes );
  1099. for( unsigned ii = 0; ii < netBuffer.size(); ii++ )
  1100. aNames.Add( netBuffer[ii]->GetNetname() );
  1101. return netBuffer.size();
  1102. }
  1103. bool BOARD::Save( FILE* aFile ) const
  1104. {
  1105. bool rc = false;
  1106. BOARD_ITEM* item;
  1107. // save the nets
  1108. for( unsigned ii = 0; ii < m_NetInfo->GetCount(); ii++ )
  1109. if( !m_NetInfo->GetNetItem( ii )->Save( aFile ) )
  1110. goto out;
  1111. // Saved nets do not include netclass names, so save netclasses after nets.
  1112. m_NetClasses.Save( aFile );
  1113. // save the modules
  1114. for( item = m_Modules; item; item = item->Next() )
  1115. if( !item->Save( aFile ) )
  1116. goto out;
  1117. for( item = m_Drawings; item; item = item->Next() )
  1118. {
  1119. switch( item->Type() )
  1120. {
  1121. case TYPE_TEXTE:
  1122. case TYPE_DRAWSEGMENT:
  1123. case TYPE_MIRE:
  1124. case TYPE_DIMENSION:
  1125. if( !item->Save( aFile ) )
  1126. goto out;
  1127. break;
  1128. default:
  1129. // future: throw exception here
  1130. #if defined(DEBUG)
  1131. printf( "BOARD::Save() ignoring m_Drawings type %d\n",
  1132. item->Type() );
  1133. #endif
  1134. break;
  1135. }
  1136. }
  1137. // do not save MARKER_PCBs, they can be regenerated easily
  1138. // save the tracks & vias
  1139. fprintf( aFile, "$TRACK\n" );
  1140. for( item = m_Track; item; item = item->Next() )
  1141. if( !item->Save( aFile ) )
  1142. goto out;
  1143. fprintf( aFile, "$EndTRACK\n" );
  1144. // save the zones
  1145. fprintf( aFile, "$ZONE\n" );
  1146. for( item = m_Zone; item; item = item->Next() )
  1147. if( !item->Save( aFile ) )
  1148. goto out;
  1149. fprintf( aFile, "$EndZONE\n" );
  1150. // save the zone edges
  1151. for( unsigned ii = 0; ii < m_ZoneDescriptorList.size(); ii++ )
  1152. {
  1153. ZONE_CONTAINER* edge_zone = m_ZoneDescriptorList[ii];
  1154. edge_zone->Save( aFile );
  1155. }
  1156. if( fprintf( aFile, "$EndBOARD\n" ) != sizeof("$EndBOARD\n") - 1 )
  1157. goto out;
  1158. rc = true; // wrote all OK
  1159. out:
  1160. return rc;
  1161. }
  1162. /**
  1163. * Function RedrawAreasOutlines
  1164. * Redraw all areas outlines on layer aLayer ( redraw all if aLayer < 0 )
  1165. */
  1166. void BOARD::RedrawAreasOutlines( WinEDA_DrawPanel* panel,
  1167. wxDC* aDC,
  1168. int aDrawMode,
  1169. int aLayer )
  1170. {
  1171. if( !aDC )
  1172. return;
  1173. for( int ii = 0; ii < GetAreaCount(); ii++ )
  1174. {
  1175. ZONE_CONTAINER* edge_zone = GetArea( ii );
  1176. if( (aLayer < 0) || ( aLayer == edge_zone->GetLayer() ) )
  1177. edge_zone->Draw( panel, aDC, aDrawMode );
  1178. }
  1179. }
  1180. /**
  1181. * Function RedrawFilledAreas
  1182. * Redraw all areas outlines on layer aLayer ( redraw all if aLayer < 0 )
  1183. */
  1184. void BOARD::RedrawFilledAreas( WinEDA_DrawPanel* panel,
  1185. wxDC* aDC,
  1186. int aDrawMode,
  1187. int aLayer )
  1188. {
  1189. if( !aDC )
  1190. return;
  1191. for( int ii = 0; ii < GetAreaCount(); ii++ )
  1192. {
  1193. ZONE_CONTAINER* edge_zone = GetArea( ii );
  1194. if( (aLayer < 0) || ( aLayer == edge_zone->GetLayer() ) )
  1195. edge_zone->DrawFilledArea( panel, aDC, aDrawMode );
  1196. }
  1197. }
  1198. /**
  1199. * Function HitTestForAnyFilledArea
  1200. * tests if the given wxPoint is within the bounds of a filled area of this
  1201. * zone.
  1202. * the test is made on zones on layer from aStartLayer to aEndLayer
  1203. * Note: if a zone has its flag BUSY (in .m_State) is set, it is ignored.
  1204. * @param refPos A wxPoint to test
  1205. * @param aStartLayer the first layer to test
  1206. * @param aEndLayer the last layer (-1 to ignore it) to test
  1207. * @return ZONE_CONTAINER* return a pointer to the ZONE_CONTAINER found, else
  1208. * NULL
  1209. */
  1210. ZONE_CONTAINER* BOARD::HitTestForAnyFilledArea( const wxPoint& aRefPos,
  1211. int aStartLayer,
  1212. int aEndLayer )
  1213. {
  1214. if( aEndLayer < 0 )
  1215. aEndLayer = aStartLayer;
  1216. if( aEndLayer < aStartLayer )
  1217. EXCHG( aEndLayer, aStartLayer );
  1218. for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ )
  1219. {
  1220. ZONE_CONTAINER* area = m_ZoneDescriptorList[ia];
  1221. int layer = area->GetLayer();
  1222. if( (layer < aStartLayer) || (layer > aEndLayer) )
  1223. continue;
  1224. if( area->GetState( BUSY ) ) // In locate functions we must skip
  1225. // tagged items with BUSY flag set.
  1226. continue;
  1227. if( area->HitTestFilledArea( aRefPos ) )
  1228. return area;
  1229. }
  1230. return NULL;
  1231. }
  1232. /**
  1233. * Function SetAreasNetCodesFromNetNames
  1234. * Set the .m_NetCode member of all copper areas, according to the area Net
  1235. * Name
  1236. * The SetNetCodesFromNetNames is an equivalent to net name, for fast
  1237. * comparisons.
  1238. * However the Netcode is an arbitrary equivalence, it must be set after each
  1239. * netlist read
  1240. * or net change
  1241. * Must be called after pad netcodes are calculated
  1242. * @return : error count
  1243. * For non copper areas, netcode is set to 0
  1244. */
  1245. int BOARD::SetAreasNetCodesFromNetNames( void )
  1246. {
  1247. int error_count = 0;
  1248. for( int ii = 0; ii < GetAreaCount(); ii++ )
  1249. {
  1250. if( !GetArea( ii )->IsOnCopperLayer() )
  1251. {
  1252. GetArea( ii )->SetNet( 0 );
  1253. continue;
  1254. }
  1255. if( GetArea( ii )->GetNet() != 0 ) // i.e. if this zone is
  1256. // connected to a net
  1257. {
  1258. const NETINFO_ITEM* net = FindNet( GetArea( ii )->m_Netname );
  1259. if( net )
  1260. {
  1261. GetArea( ii )->SetNet( net->GetNet() );
  1262. }
  1263. else
  1264. {
  1265. error_count++;
  1266. GetArea( ii )->SetNet( -1 ); // keep Net Name and set
  1267. // m_NetCode to -1 : error flag
  1268. }
  1269. }
  1270. }
  1271. return error_count;
  1272. }
  1273. #if defined(DEBUG)
  1274. /**
  1275. * Function Show
  1276. * is used to output the object tree, currently for debugging only.
  1277. * @param nestLevel An aid to prettier tree indenting, and is the level
  1278. * of nesting of this object within the overall tree.
  1279. * @param os The ostream& to output to.
  1280. */
  1281. void BOARD::Show( int nestLevel, std::ostream& os )
  1282. {
  1283. BOARD_ITEM* p;
  1284. // for now, make it look like XML:
  1285. NestedSpace( nestLevel,
  1286. os ) << '<' << GetClass().Lower().mb_str() << ">\n";
  1287. // specialization of the output:
  1288. NestedSpace( nestLevel + 1, os ) << "<modules>\n";
  1289. p = m_Modules;
  1290. for( ; p; p = p->Next() )
  1291. p->Show( nestLevel + 2, os );
  1292. NestedSpace( nestLevel + 1, os ) << "</modules>\n";
  1293. NestedSpace( nestLevel + 1, os ) << "<pdrawings>\n";
  1294. p = m_Drawings;
  1295. for( ; p; p = p->Next() )
  1296. p->Show( nestLevel + 2, os );
  1297. NestedSpace( nestLevel + 1, os ) << "</pdrawings>\n";
  1298. NestedSpace( nestLevel + 1, os ) << "<tracks>\n";
  1299. p = m_Track;
  1300. for( ; p; p = p->Next() )
  1301. p->Show( nestLevel + 2, os );
  1302. NestedSpace( nestLevel + 1, os ) << "</tracks>\n";
  1303. NestedSpace( nestLevel + 1, os ) << "<zones>\n";
  1304. p = m_Zone;
  1305. for( ; p; p = p->Next() )
  1306. p->Show( nestLevel + 2, os );
  1307. NestedSpace( nestLevel + 1, os ) << "</zones>\n";
  1308. /*
  1309. * NestedSpace( nestLevel+1, os ) << "<zone_container>\n";
  1310. * for( ZONE_CONTAINERS::iterator i=m_ZoneDescriptorList.begin();
  1311. * i!=m_ZoneDescriptorList.end(); ++i )
  1312. * (*i)->Show( nestLevel+2, os );
  1313. * NestedSpace( nestLevel+1, os ) << "</zone_container>\n";
  1314. */
  1315. p = (BOARD_ITEM*) m_Son;
  1316. for( ; p; p = p->Next() )
  1317. {
  1318. p->Show( nestLevel + 1, os );
  1319. }
  1320. NestedSpace( nestLevel, os ) << "</" << GetClass().Lower().mb_str()
  1321. << ">\n";
  1322. }
  1323. #endif