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.

1063 lines
29 KiB

17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
19 years ago
  1. /****************************************************/
  2. /* class_module.cpp : MODULE class implementation. */
  3. /****************************************************/
  4. #include "fctsys.h"
  5. #include "gr_basic.h"
  6. #include "wxstruct.h"
  7. #include "common.h"
  8. #include "plot_common.h"
  9. #include "class_drawpanel.h"
  10. #include "trigo.h"
  11. #include "confirm.h"
  12. #include "kicad_string.h"
  13. #include "pcbcommon.h"
  14. #include "pcbnew.h"
  15. #include "class_board_design_settings.h"
  16. #include "colors_selection.h"
  17. #include "drag.h"
  18. #include "3d_struct.h"
  19. #include "protos.h"
  20. #include "richio.h"
  21. #include "filter_reader.h"
  22. /*********************************************/
  23. /* Class MODULE : describes a pcb component. */
  24. /*********************************************/
  25. MODULE::MODULE( BOARD* parent ) :
  26. BOARD_ITEM( parent, TYPE_MODULE )
  27. {
  28. m_Attributs = MOD_DEFAULT;
  29. m_Layer = LAYER_N_FRONT;
  30. m_Orient = 0;
  31. m_ModuleStatus = 0;
  32. flag = 0;
  33. m_CntRot90 = m_CntRot180 = 0;
  34. m_Surface = 0.0;
  35. m_Link = 0;
  36. m_LastEdit_Time = time( NULL );
  37. m_LocalClearance = 0;
  38. m_LocalSolderMaskMargin = 0;
  39. m_LocalSolderPasteMargin = 0;
  40. m_LocalSolderPasteMarginRatio = 0.0;
  41. m_Reference = new TEXTE_MODULE( this, TEXT_is_REFERENCE );
  42. m_Value = new TEXTE_MODULE( this, TEXT_is_VALUE );
  43. // Reserve one void 3D entry, to avoid problems with void list
  44. m_3D_Drawings.PushBack( new S3D_MASTER( this ) );
  45. }
  46. MODULE::~MODULE()
  47. {
  48. delete m_Reference;
  49. delete m_Value;
  50. }
  51. /* Draw the anchor cross (vertical)
  52. * Must be done after the pads, because drawing the hole will erase overwrite
  53. * every thing already drawn.
  54. */
  55. void MODULE::DrawAncre( EDA_DRAW_PANEL* panel, wxDC* DC, const wxPoint& offset,
  56. int dim_ancre, int draw_mode )
  57. {
  58. int anchor_size = DC->DeviceToLogicalXRel( dim_ancre );
  59. GRSetDrawMode( DC, draw_mode );
  60. if( GetBoard()->IsElementVisible( ANCHOR_VISIBLE ) )
  61. {
  62. int color = g_ColorsSettings.GetItemColor( ANCHOR_VISIBLE );
  63. GRLine( &panel->m_ClipBox, DC,
  64. m_Pos.x - offset.x - anchor_size, m_Pos.y - offset.y,
  65. m_Pos.x - offset.x + anchor_size, m_Pos.y - offset.y,
  66. 0, color );
  67. GRLine( &panel->m_ClipBox, DC,
  68. m_Pos.x - offset.x, m_Pos.y - offset.y - anchor_size,
  69. m_Pos.x - offset.x, m_Pos.y - offset.y + anchor_size,
  70. 0, color );
  71. }
  72. }
  73. void MODULE::Copy( MODULE* aModule )
  74. {
  75. m_Pos = aModule->m_Pos;
  76. m_Layer = aModule->m_Layer;
  77. m_LibRef = aModule->m_LibRef;
  78. m_Attributs = aModule->m_Attributs;
  79. m_Orient = aModule->m_Orient;
  80. m_BoundaryBox = aModule->m_BoundaryBox;
  81. m_PadNum = aModule->m_PadNum;
  82. m_CntRot90 = aModule->m_CntRot90;
  83. m_CntRot180 = aModule->m_CntRot180;
  84. m_LastEdit_Time = aModule->m_LastEdit_Time;
  85. m_Link = aModule->m_Link;
  86. m_Path = aModule->m_Path; //is this correct behavior?
  87. m_TimeStamp = GetTimeStamp();
  88. m_LocalSolderMaskMargin = aModule->m_LocalSolderMaskMargin;
  89. m_LocalSolderPasteMargin = aModule->m_LocalSolderPasteMargin;
  90. m_LocalSolderPasteMarginRatio = aModule->m_LocalSolderPasteMarginRatio;
  91. /* Copy reference and value. */
  92. m_Reference->Copy( aModule->m_Reference );
  93. m_Value->Copy( aModule->m_Value );
  94. /* Copy auxiliary data: Pads */
  95. m_Pads.DeleteAll();
  96. for( D_PAD* pad = aModule->m_Pads; pad; pad = pad->Next() )
  97. {
  98. D_PAD* newpad = new D_PAD( this );
  99. newpad->Copy( pad );
  100. m_Pads.PushBack( newpad );
  101. }
  102. /* Copy auxiliary data: Drawings */
  103. m_Drawings.DeleteAll();
  104. for( BOARD_ITEM* item = aModule->m_Drawings; item; item = item->Next() )
  105. {
  106. switch( item->Type() )
  107. {
  108. case TYPE_TEXTE_MODULE:
  109. TEXTE_MODULE * textm;
  110. textm = new TEXTE_MODULE( this );
  111. textm->Copy( (TEXTE_MODULE*) item );
  112. m_Drawings.PushBack( textm );
  113. break;
  114. case TYPE_EDGE_MODULE:
  115. EDGE_MODULE * edge;
  116. edge = new EDGE_MODULE( this );
  117. edge->Copy( (EDGE_MODULE*) item );
  118. m_Drawings.PushBack( edge );
  119. break;
  120. default:
  121. wxMessageBox( wxT( "MODULE::Copy() Internal Err: unknown type" ) );
  122. break;
  123. }
  124. }
  125. /* Copy auxiliary data: 3D_Drawings info */
  126. m_3D_Drawings.DeleteAll();
  127. // Ensure there is one (or more) item in m_3D_Drawings
  128. m_3D_Drawings.PushBack( new S3D_MASTER( this ) ); // push a void item
  129. for( S3D_MASTER* item = aModule->m_3D_Drawings; item; item = item->Next() )
  130. {
  131. if( item->m_Shape3DName.IsEmpty() ) // do not copy empty shapes.
  132. continue;
  133. S3D_MASTER* t3d = m_3D_Drawings;
  134. if( t3d && t3d->m_Shape3DName.IsEmpty() ) // The first entry can
  135. // exist, but is empty :
  136. // use it.
  137. t3d->Copy( item );
  138. else
  139. {
  140. t3d = new S3D_MASTER( this );
  141. t3d->Copy( item );
  142. m_3D_Drawings.PushBack( t3d );
  143. }
  144. }
  145. m_Doc = aModule->m_Doc;
  146. m_KeyWord = aModule->m_KeyWord;
  147. }
  148. /**
  149. * Function Draw
  150. * Draws the footprint to the current Device Context
  151. * @param aPanel = draw panel, Used to know the clip box
  152. * @param aDC = Current Device Context
  153. * @param aDrawMode = GR_OR, GR_XOR..
  154. * @param aOffset = draw offset (usually wxPoint(0,0)
  155. */
  156. void MODULE::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, int aDrawMode, const wxPoint& aOffset )
  157. {
  158. if( (m_Flags & DO_NOT_DRAW) || (m_Flags & IS_MOVED) )
  159. return;
  160. for( D_PAD* pad = m_Pads; pad; pad = pad->Next() )
  161. {
  162. if( pad->m_Flags & IS_MOVED )
  163. continue;
  164. pad->Draw( aPanel, aDC, aDrawMode, aOffset );
  165. }
  166. BOARD* brd = GetBoard();
  167. // Draws footprint anchor
  168. DrawAncre( aPanel, aDC, aOffset, DIM_ANCRE_MODULE, aDrawMode );
  169. /* Draw graphic items */
  170. if( brd->IsElementVisible( MOD_REFERENCES_VISIBLE ) )
  171. {
  172. if( !(m_Reference->m_Flags & IS_MOVED) )
  173. m_Reference->Draw( aPanel, aDC, aDrawMode, aOffset );
  174. }
  175. if( brd->IsElementVisible( MOD_VALUES_VISIBLE ) )
  176. {
  177. if( !(m_Value->m_Flags & IS_MOVED) )
  178. m_Value->Draw( aPanel, aDC, aDrawMode, aOffset );
  179. }
  180. for( BOARD_ITEM* item = m_Drawings; item; item = item->Next() )
  181. {
  182. if( item->m_Flags & IS_MOVED )
  183. continue;
  184. switch( item->Type() )
  185. {
  186. case TYPE_TEXTE_MODULE:
  187. case TYPE_EDGE_MODULE:
  188. item->Draw( aPanel, aDC, aDrawMode, aOffset );
  189. break;
  190. default:
  191. break;
  192. }
  193. }
  194. }
  195. /**
  196. * Function DrawEdgesOnly
  197. * Draws the footprint edges only to the current Device Context
  198. * @param panel = The active Draw Panel (used to know the clip box)
  199. * @param DC = current Device Context
  200. * @param offset = draw offset (usually wxPoint(0,0)
  201. * @param draw_mode = GR_OR, GR_XOR, GR_AND
  202. */
  203. void MODULE::DrawEdgesOnly( EDA_DRAW_PANEL* panel, wxDC* DC, const wxPoint& offset, int draw_mode )
  204. {
  205. for( BOARD_ITEM* item = m_Drawings; item; item = item->Next() )
  206. {
  207. switch( item->Type() )
  208. {
  209. case TYPE_EDGE_MODULE:
  210. item->Draw( panel, DC, draw_mode, offset );
  211. break;
  212. default:
  213. break;
  214. }
  215. }
  216. }
  217. bool MODULE::Save( FILE* aFile ) const
  218. {
  219. char statusTxt[8];
  220. BOARD_ITEM* item;
  221. if( GetState( DELETED ) )
  222. return true;
  223. bool rc = false;
  224. fprintf( aFile, "$MODULE %s\n", CONV_TO_UTF8( m_LibRef ) );
  225. memset( statusTxt, 0, sizeof(statusTxt) );
  226. if( IsLocked() )
  227. statusTxt[0] = 'F';
  228. else
  229. statusTxt[0] = '~';
  230. if( m_ModuleStatus & MODULE_is_PLACED )
  231. statusTxt[1] = 'P';
  232. else
  233. statusTxt[1] = '~';
  234. fprintf( aFile, "Po %d %d %d %d %8.8lX %8.8lX %s\n",
  235. m_Pos.x, m_Pos.y,
  236. m_Orient, m_Layer, m_LastEdit_Time,
  237. m_TimeStamp, statusTxt );
  238. fprintf( aFile, "Li %s\n", CONV_TO_UTF8( m_LibRef ) );
  239. if( !m_Doc.IsEmpty() )
  240. {
  241. fprintf( aFile, "Cd %s\n", CONV_TO_UTF8( m_Doc ) );
  242. }
  243. if( !m_KeyWord.IsEmpty() )
  244. {
  245. fprintf( aFile, "Kw %s\n", CONV_TO_UTF8( m_KeyWord ) );
  246. }
  247. fprintf( aFile, "Sc %8.8lX\n", m_TimeStamp );
  248. fprintf( aFile, "AR %s\n", CONV_TO_UTF8( m_Path ) );
  249. fprintf( aFile, "Op %X %X 0\n", m_CntRot90, m_CntRot180 );
  250. if( m_LocalSolderMaskMargin != 0 )
  251. fprintf( aFile, ".SolderMask %d\n", m_LocalSolderMaskMargin );
  252. if( m_LocalSolderPasteMargin != 0 )
  253. fprintf( aFile, ".SolderPaste %d\n", m_LocalSolderPasteMargin );
  254. if( m_LocalSolderPasteMarginRatio != 0 )
  255. fprintf( aFile, ".SolderPasteRatio %g\n", m_LocalSolderPasteMarginRatio );
  256. if( m_LocalClearance != 0 )
  257. fprintf( aFile, ".LocalClearance %d\n", m_LocalClearance );
  258. // attributes
  259. if( m_Attributs != MOD_DEFAULT )
  260. {
  261. fprintf( aFile, "At " );
  262. if( m_Attributs & MOD_CMS )
  263. fprintf( aFile, "SMD " );
  264. if( m_Attributs & MOD_VIRTUAL )
  265. fprintf( aFile, "VIRTUAL " );
  266. fprintf( aFile, "\n" );
  267. }
  268. // save reference
  269. if( !m_Reference->Save( aFile ) )
  270. goto out;
  271. // save value
  272. if( !m_Value->Save( aFile ) )
  273. goto out;
  274. // save drawing elements
  275. for( item = m_Drawings; item; item = item->Next() )
  276. {
  277. switch( item->Type() )
  278. {
  279. case TYPE_TEXTE_MODULE:
  280. case TYPE_EDGE_MODULE:
  281. if( !item->Save( aFile ) )
  282. goto out;
  283. break;
  284. default:
  285. #if defined(DEBUG)
  286. printf( "MODULE::Save() ignoring type %d\n", item->Type() );
  287. #endif
  288. break;
  289. }
  290. }
  291. // save the pads
  292. for( item = m_Pads; item; item = item->Next() )
  293. if( !item->Save( aFile ) )
  294. goto out;
  295. Write_3D_Descr( aFile );
  296. fprintf( aFile, "$EndMODULE %s\n", CONV_TO_UTF8( m_LibRef ) );
  297. rc = true;
  298. out:
  299. return rc;
  300. }
  301. /* Save the description of 3D MODULE
  302. */
  303. int MODULE::Write_3D_Descr( FILE* File ) const
  304. {
  305. char buf[512];
  306. for( S3D_MASTER* t3D = m_3D_Drawings; t3D; t3D = t3D->Next() )
  307. {
  308. if( !t3D->m_Shape3DName.IsEmpty() )
  309. {
  310. fprintf( File, "$SHAPE3D\n" );
  311. fprintf( File, "Na \"%s\"\n", CONV_TO_UTF8( t3D->m_Shape3DName ) );
  312. sprintf( buf, "Sc %lf %lf %lf\n",
  313. t3D->m_MatScale.x,
  314. t3D->m_MatScale.y,
  315. t3D->m_MatScale.z );
  316. fprintf( File, "%s", to_point( buf ) );
  317. sprintf( buf, "Of %lf %lf %lf\n",
  318. t3D->m_MatPosition.x,
  319. t3D->m_MatPosition.y,
  320. t3D->m_MatPosition.z );
  321. fprintf( File, "%s", to_point( buf ) );
  322. sprintf( buf, "Ro %lf %lf %lf\n",
  323. t3D->m_MatRotation.x,
  324. t3D->m_MatRotation.y,
  325. t3D->m_MatRotation.z );
  326. fprintf( File, "%s", to_point( buf ) );
  327. fprintf( File, "$EndSHAPE3D\n" );
  328. }
  329. }
  330. return 0;
  331. }
  332. /* Read 3D module from file. (Ascii)
  333. * The 1st line of descr ($MODULE) is assumed to be already read
  334. * Returns 0 if OK
  335. */
  336. int MODULE::Read_3D_Descr( LINE_READER* aReader )
  337. {
  338. char* Line = aReader->Line();
  339. char* text = Line + 3;
  340. S3D_MASTER* t3D = m_3D_Drawings;
  341. if( !t3D->m_Shape3DName.IsEmpty() )
  342. {
  343. S3D_MASTER* n3D = new S3D_MASTER( this );
  344. m_3D_Drawings.PushBack( n3D );
  345. t3D = n3D;
  346. }
  347. while( aReader->ReadLine() )
  348. {
  349. Line = aReader->Line();
  350. switch( Line[0] )
  351. {
  352. case '$':
  353. if( Line[1] == 'E' )
  354. return 0;
  355. return 1;
  356. case 'N': // Shape File Name
  357. {
  358. char buf[512];
  359. ReadDelimitedText( buf, text, 512 );
  360. t3D->m_Shape3DName = CONV_FROM_UTF8( buf );
  361. break;
  362. }
  363. case 'S': // Scale
  364. sscanf( text, "%lf %lf %lf\n",
  365. &t3D->m_MatScale.x,
  366. &t3D->m_MatScale.y,
  367. &t3D->m_MatScale.z );
  368. break;
  369. case 'O': // Offset
  370. sscanf( text, "%lf %lf %lf\n",
  371. &t3D->m_MatPosition.x,
  372. &t3D->m_MatPosition.y,
  373. &t3D->m_MatPosition.z );
  374. break;
  375. case 'R': // Rotation
  376. sscanf( text, "%lf %lf %lf\n",
  377. &t3D->m_MatRotation.x,
  378. &t3D->m_MatRotation.y,
  379. &t3D->m_MatRotation.z );
  380. break;
  381. default:
  382. break;
  383. }
  384. }
  385. return 1;
  386. }
  387. /* Read a MODULE description
  388. * The first description line ($MODULE) is already read
  389. * @return 0 if no error
  390. */
  391. int MODULE::ReadDescr( LINE_READER* aReader )
  392. {
  393. char* Line;
  394. char BufLine[256], BufCar1[128], * PtLine;
  395. int itmp1, itmp2;
  396. while( aReader->ReadLine() )
  397. {
  398. Line = aReader->Line();
  399. if( Line[0] == '$' )
  400. {
  401. if( Line[1] == 'E' )
  402. break;
  403. if( Line[1] == 'P' )
  404. {
  405. D_PAD* pad = new D_PAD( this );
  406. pad->ReadDescr( aReader );
  407. RotatePoint( &pad->m_Pos, m_Orient );
  408. pad->m_Pos.x += m_Pos.x;
  409. pad->m_Pos.y += m_Pos.y;
  410. m_Pads.PushBack( pad );
  411. continue;
  412. }
  413. if( Line[1] == 'S' )
  414. Read_3D_Descr( aReader );
  415. }
  416. if( strlen( Line ) < 4 )
  417. continue;
  418. PtLine = Line + 3;
  419. /* Decode the first code of the current line and read the
  420. * corresponding data
  421. */
  422. switch( Line[0] )
  423. {
  424. case 'P':
  425. memset( BufCar1, 0, sizeof(BufCar1) );
  426. sscanf( PtLine, "%d %d %d %d %lX %lX %s",
  427. &m_Pos.x, &m_Pos.y,
  428. &m_Orient, &m_Layer,
  429. &m_LastEdit_Time, &m_TimeStamp, BufCar1 );
  430. m_ModuleStatus = 0;
  431. if( BufCar1[0] == 'F' )
  432. SetLocked( true );
  433. if( BufCar1[1] == 'P' )
  434. m_ModuleStatus |= MODULE_is_PLACED;
  435. break;
  436. case 'L': /* Li = read the library name of the footprint */
  437. *BufLine = 0;
  438. sscanf( PtLine, " %s", BufLine );
  439. m_LibRef = CONV_FROM_UTF8( BufLine );
  440. break;
  441. case 'S':
  442. sscanf( PtLine, " %lX", &m_TimeStamp );
  443. break;
  444. case 'O': /* (Op)tions for auto placement */
  445. itmp1 = itmp2 = 0;
  446. sscanf( PtLine, " %X %X", &itmp1, &itmp2 );
  447. m_CntRot180 = itmp2 & 0x0F;
  448. if( m_CntRot180 > 10 )
  449. m_CntRot180 = 10;
  450. m_CntRot90 = itmp1 & 0x0F;
  451. if( m_CntRot90 > 10 )
  452. m_CntRot90 = 0;
  453. itmp1 = (itmp1 >> 4) & 0x0F;
  454. if( itmp1 > 10 )
  455. itmp1 = 0;
  456. m_CntRot90 |= itmp1 << 4;
  457. break;
  458. case 'A':
  459. if( Line[1] == 't' )
  460. {
  461. /* At = (At)tributes of module */
  462. if( strstr( PtLine, "SMD" ) )
  463. m_Attributs |= MOD_CMS;
  464. if( strstr( PtLine, "VIRTUAL" ) )
  465. m_Attributs |= MOD_VIRTUAL;
  466. }
  467. if( Line[1] == 'R' )
  468. {
  469. // alternate reference, e.g. /478C2408/478AD1B6
  470. sscanf( PtLine, " %s", BufLine );
  471. m_Path = CONV_FROM_UTF8( BufLine );
  472. }
  473. break;
  474. case 'T': /* Read a footprint text description (ref, value, or
  475. * drawing */
  476. TEXTE_MODULE * textm;
  477. sscanf( Line + 1, "%d", &itmp1 );
  478. if( itmp1 == TEXT_is_REFERENCE )
  479. textm = m_Reference;
  480. else if( itmp1 == TEXT_is_VALUE )
  481. textm = m_Value;
  482. else /* text is a drawing */
  483. {
  484. textm = new TEXTE_MODULE( this );
  485. m_Drawings.PushBack( textm );
  486. }
  487. textm->ReadDescr( aReader );
  488. break;
  489. case 'D': /* read a drawing item */
  490. EDGE_MODULE * edge;
  491. edge = new EDGE_MODULE( this );
  492. m_Drawings.PushBack( edge );
  493. edge->ReadDescr( aReader );
  494. edge->SetDrawCoord();
  495. break;
  496. case 'C': /* read documentation data */
  497. m_Doc = CONV_FROM_UTF8( StrPurge( PtLine ) );
  498. break;
  499. case 'K': /* Read key words */
  500. m_KeyWord = CONV_FROM_UTF8( StrPurge( PtLine ) );
  501. break;
  502. case '.': /* Read specific data */
  503. if( strnicmp( Line, ".SolderMask ", 12 ) == 0 )
  504. m_LocalSolderMaskMargin = atoi( Line + 12 );
  505. else if( strnicmp( Line, ".SolderPaste ", 13 ) == 0 )
  506. m_LocalSolderPasteMargin = atoi( Line + 13 );
  507. else if( strnicmp( Line, ".SolderPasteRatio ", 18 ) == 0 )
  508. m_LocalSolderPasteMarginRatio = atof( Line + 18 );
  509. else if( strnicmp( Line, ".LocalClearance ", 16 ) == 0 )
  510. m_LocalClearance = atoi( Line + 16 );
  511. break;
  512. default:
  513. break;
  514. }
  515. }
  516. /* Recalculate the bounding box */
  517. Set_Rectangle_Encadrement();
  518. return 0;
  519. }
  520. /* Update the bounding rectangle of the module
  521. *
  522. * The bounding box includes outlines and pads, but not the fields.
  523. * The rectangle is:
  524. * for orientation 0
  525. * coordinates relative to the module anchor.
  526. */
  527. void MODULE::Set_Rectangle_Encadrement()
  528. {
  529. int width;
  530. int cx, cy, uxf, uyf, rayon;
  531. int xmax, ymax;
  532. int xmin, ymin;
  533. /* Initial coordinates of the module has a nonzero limit value. */
  534. xmin = ymin = -250;
  535. xmax = ymax = 250;
  536. for( EDGE_MODULE* edge = (EDGE_MODULE*) m_Drawings.GetFirst();
  537. edge; edge = edge->Next() )
  538. {
  539. if( edge->Type() != TYPE_EDGE_MODULE )
  540. continue;
  541. width = edge->m_Width / 2;
  542. switch( edge->m_Shape )
  543. {
  544. case S_ARC:
  545. case S_CIRCLE:
  546. {
  547. cx = edge->m_Start0.x;
  548. cy = edge->m_Start0.y; // center
  549. uxf = edge->m_End0.x;
  550. uyf = edge->m_End0.y;
  551. rayon = (int) hypot( (double) ( cx - uxf ), (double) ( cy - uyf ) );
  552. rayon += width;
  553. xmin = MIN( xmin, cx - rayon );
  554. ymin = MIN( ymin, cy - rayon );
  555. xmax = MAX( xmax, cx + rayon );
  556. ymax = MAX( ymax, cy + rayon );
  557. break;
  558. }
  559. case S_SEGMENT:
  560. xmin = MIN( xmin, edge->m_Start0.x - width );
  561. xmin = MIN( xmin, edge->m_End0.x - width );
  562. ymin = MIN( ymin, edge->m_Start0.y - width );
  563. ymin = MIN( ymin, edge->m_End0.y - width );
  564. xmax = MAX( xmax, edge->m_Start0.x + width );
  565. xmax = MAX( xmax, edge->m_End0.x + width );
  566. ymax = MAX( ymax, edge->m_Start0.y + width );
  567. ymax = MAX( ymax, edge->m_End0.y + width );
  568. break;
  569. case S_POLYGON:
  570. for( unsigned ii = 0; ii < edge->m_PolyPoints.size(); ii++ )
  571. {
  572. wxPoint pt = edge->m_PolyPoints[ii];
  573. xmin = MIN( xmin, (pt.x - width) );
  574. ymin = MIN( ymin, (pt.y - width) );
  575. xmax = MAX( xmax, (pt.x + width) );
  576. ymax = MAX( ymax, (pt.y + width) );
  577. }
  578. break;
  579. }
  580. }
  581. /* Pads: find the min and max coordinates and update the bounding box.
  582. */
  583. for( D_PAD* pad = m_Pads; pad; pad = pad->Next() )
  584. {
  585. rayon = pad->m_ShapeMaxRadius;
  586. cx = pad->m_Pos0.x;
  587. cy = pad->m_Pos0.y;
  588. xmin = MIN( xmin, cx - rayon );
  589. ymin = MIN( ymin, cy - rayon );
  590. xmax = MAX( xmax, cx + rayon );
  591. ymax = MAX( ymax, cy + rayon );
  592. }
  593. m_BoundaryBox.m_Pos.x = xmin;
  594. m_BoundaryBox.m_Pos.y = ymin;
  595. m_BoundaryBox.SetWidth( xmax - xmin );
  596. m_BoundaryBox.SetHeight( ymax - ymin );
  597. }
  598. EDA_Rect MODULE::GetFootPrintRect() const
  599. {
  600. EDA_Rect area;
  601. area.m_Pos = m_Pos;
  602. area.SetEnd( m_Pos );
  603. area.Inflate( 500 ); // Give a min size
  604. for( EDGE_MODULE* edge = (EDGE_MODULE*) m_Drawings.GetFirst(); edge; edge = edge->Next() )
  605. {
  606. if( edge->Type() != TYPE_EDGE_MODULE ) // Shoud not occur
  607. continue;
  608. area.Merge( edge->GetBoundingBox() );
  609. }
  610. for( D_PAD* pad = m_Pads; pad; pad = pad->Next() )
  611. {
  612. area.Merge( pad->GetBoundingBox() );
  613. }
  614. return area;
  615. }
  616. /* Equivalent to Module::Set_Rectangle_Encadrement() but in board coordinates:
  617. * Updates the module bounding box on the board
  618. * The rectangle is the rectangle with outlines and pads, but not the fields
  619. * Also updates the surface (.M_Surface) module.
  620. */
  621. void MODULE::SetRectangleExinscrit()
  622. {
  623. m_RealBoundaryBox = GetFootPrintRect();
  624. m_Surface = ABS( (double) m_RealBoundaryBox.GetWidth() * m_RealBoundaryBox.GetHeight() );
  625. }
  626. /**
  627. * Function GetBoundingBox
  628. * returns the full bounding box of this Footprint, including fields
  629. * Mainly used to redraw the screen area occupied by the footprint
  630. */
  631. EDA_Rect MODULE::GetBoundingBox() const
  632. {
  633. EDA_Rect area = GetFootPrintRect();;
  634. // Calculate extended area including text field:
  635. EDA_Rect text_area;
  636. text_area = m_Reference->GetBoundingBox();
  637. area.Merge( text_area );
  638. text_area = m_Value->GetBoundingBox();
  639. area.Merge( text_area );
  640. for( EDGE_MODULE* edge = (EDGE_MODULE*) m_Drawings.GetFirst(); edge; edge = edge->Next() )
  641. {
  642. if( edge->Type() != TYPE_TEXTE_MODULE )
  643. continue;
  644. text_area = ( (TEXTE_MODULE*) edge )->GetBoundingBox();
  645. area.Merge( text_area );
  646. }
  647. // Add the Clearance shape size: (shape around the pads when the
  648. // clearance is shown. Not optimized, but the draw cost is small
  649. // (perhaps smaller than optimization).
  650. int biggest_clearance = GetBoard()->GetBiggestClearanceValue();
  651. area.Inflate( biggest_clearance );
  652. return area;
  653. }
  654. /* Virtual function, from EDA_ITEM.
  655. * display module info on MsgPanel
  656. */
  657. void MODULE::DisplayInfo( EDA_DRAW_FRAME* frame )
  658. {
  659. int nbpad;
  660. char bufcar[512], Line[512];
  661. bool flag = FALSE;
  662. wxString msg;
  663. BOARD* board = GetBoard();
  664. frame->EraseMsgBox();
  665. if( frame->m_Ident != PCB_FRAME )
  666. flag = TRUE;
  667. frame->AppendMsgPanel( m_Reference->m_Text, m_Value->m_Text, DARKCYAN );
  668. if( flag ) // Display last date the component was edited( useful in Module Editor)
  669. {
  670. time_t edit_time = m_LastEdit_Time;
  671. strcpy( Line, ctime( &edit_time ) );
  672. strtok( Line, " \n\r" );
  673. strcpy( bufcar, strtok( NULL, " \n\r" ) ); strcat( bufcar, " " );
  674. strcat( bufcar, strtok( NULL, " \n\r" ) ); strcat( bufcar, ", " );
  675. strtok( NULL, " \n\r" );
  676. strcat( bufcar, strtok( NULL, " \n\r" ) );
  677. msg = CONV_FROM_UTF8( bufcar );
  678. frame->AppendMsgPanel( _( "Last Change" ), msg, BROWN );
  679. }
  680. else // display time stamp in schematic
  681. {
  682. msg.Printf( wxT( "%8.8lX" ), m_TimeStamp );
  683. frame->AppendMsgPanel( _( "Netlist path" ), m_Path, BROWN );
  684. }
  685. frame->AppendMsgPanel( _( "Layer" ), board->GetLayerName( m_Layer ), RED );
  686. EDA_ITEM* PtStruct = m_Pads;
  687. nbpad = 0;
  688. while( PtStruct )
  689. {
  690. nbpad++;
  691. PtStruct = PtStruct->Next();
  692. }
  693. msg.Printf( wxT( "%d" ), nbpad );
  694. frame->AppendMsgPanel( _( "Pads" ), msg, BLUE );
  695. msg = wxT( ".." );
  696. if( IsLocked() )
  697. msg[0] = 'L';
  698. if( m_ModuleStatus & MODULE_is_PLACED )
  699. msg[1] = 'P';
  700. frame->AppendMsgPanel( _( "Stat" ), msg, MAGENTA );
  701. msg.Printf( wxT( "%.1f" ), (float) m_Orient / 10 );
  702. frame->AppendMsgPanel( _( "Orient" ), msg, BROWN );
  703. frame->AppendMsgPanel( _( "Module" ), m_LibRef, BLUE );
  704. if( m_3D_Drawings != NULL )
  705. msg = m_3D_Drawings->m_Shape3DName;
  706. else
  707. msg = _( "No 3D shape" );
  708. frame->AppendMsgPanel( _( "3D-Shape" ), msg, RED );
  709. wxString doc = _( "Doc: " ) + m_Doc;
  710. wxString keyword = _( "KeyW: " ) + m_KeyWord;
  711. frame->AppendMsgPanel( doc, keyword, BLACK );
  712. }
  713. /**
  714. * Function HitTest
  715. * tests if the given wxPoint is within the bounds of this object.
  716. * @param refPos A wxPoint to test
  717. * @return bool - true if a hit, else false
  718. */
  719. bool MODULE::HitTest( const wxPoint& refPos )
  720. {
  721. /* Calculation of the cursor coordinate relative to module */
  722. wxPoint pos = refPos - m_Pos;
  723. RotatePoint( &pos, -m_Orient );
  724. /* Check if cursor is in the rectangle. */
  725. if( m_BoundaryBox.Contains( pos ) )
  726. return true;
  727. return false;
  728. }
  729. /**
  730. * Function HitTest (overlaid)
  731. * tests if the given EDA_Rect intersect the bounds of this object.
  732. * @param refArea : the given EDA_Rect
  733. * @return bool - true if a hit, else false
  734. */
  735. bool MODULE::HitTest( EDA_Rect& refArea )
  736. {
  737. bool is_out_of_box = false;
  738. SetRectangleExinscrit();
  739. if( m_RealBoundaryBox.m_Pos.x < refArea.GetX() )
  740. is_out_of_box = true;
  741. if( m_RealBoundaryBox.m_Pos.y < refArea.GetY() )
  742. is_out_of_box = true;
  743. if( m_RealBoundaryBox.GetRight() > refArea.GetRight() )
  744. is_out_of_box = true;
  745. if( m_RealBoundaryBox.GetBottom() > refArea.GetBottom() )
  746. is_out_of_box = true;
  747. return is_out_of_box ? false : true;
  748. }
  749. D_PAD* MODULE::FindPadByName( const wxString& aPadName ) const
  750. {
  751. wxString buf;
  752. for( D_PAD* pad = m_Pads; pad; pad = pad->Next() )
  753. {
  754. pad->ReturnStringPadName( buf );
  755. #if 1
  756. if( buf.CmpNoCase( aPadName ) == 0 ) // why case insensitive?
  757. #else
  758. if( buf == aPadName )
  759. #endif
  760. return pad;
  761. }
  762. return NULL;
  763. }
  764. // see class_module.h
  765. SEARCH_RESULT MODULE::Visit( INSPECTOR* inspector, const void* testData,
  766. const KICAD_T scanTypes[] )
  767. {
  768. KICAD_T stype;
  769. SEARCH_RESULT result = SEARCH_CONTINUE;
  770. const KICAD_T* p = scanTypes;
  771. bool done = false;
  772. #if 0 && defined(DEBUG)
  773. std::cout << GetClass().mb_str() << ' ';
  774. #endif
  775. while( !done )
  776. {
  777. stype = *p;
  778. switch( stype )
  779. {
  780. case TYPE_MODULE:
  781. result = inspector->Inspect( this, testData ); // inspect me
  782. ++p;
  783. break;
  784. case TYPE_PAD:
  785. result = IterateForward( m_Pads, inspector, testData, p );
  786. ++p;
  787. break;
  788. case TYPE_TEXTE_MODULE:
  789. result = inspector->Inspect( m_Reference, testData );
  790. if( result == SEARCH_QUIT )
  791. break;
  792. result = inspector->Inspect( m_Value, testData );
  793. if( result == SEARCH_QUIT )
  794. break;
  795. // m_Drawings can hold TYPETEXTMODULE also, so fall thru
  796. case TYPE_EDGE_MODULE:
  797. result = IterateForward( m_Drawings, inspector, testData, p );
  798. // skip over any types handled in the above call.
  799. for( ; ; )
  800. {
  801. switch( stype = *++p )
  802. {
  803. case TYPE_TEXTE_MODULE:
  804. case TYPE_EDGE_MODULE:
  805. continue;
  806. default:
  807. ;
  808. }
  809. break;
  810. }
  811. break;
  812. default:
  813. done = true;
  814. break;
  815. }
  816. if( result == SEARCH_QUIT )
  817. break;
  818. }
  819. return result;
  820. }
  821. #if defined(DEBUG)
  822. /**
  823. * Function Show
  824. * is used to output the object tree, currently for debugging only.
  825. * @param nestLevel An aid to prettier tree indenting, and is the level
  826. * of nesting of this object within the overall tree.
  827. * @param os The ostream& to output to.
  828. */
  829. void MODULE::Show( int nestLevel, std::ostream& os )
  830. {
  831. BOARD* board = GetBoard();
  832. // for now, make it look like XML, expand on this later.
  833. NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() <<
  834. " ref=\"" << m_Reference->m_Text.mb_str() << '"' <<
  835. " value=\"" << m_Value->m_Text.mb_str() << '"' <<
  836. " layer=\"" << board->GetLayerName( m_Layer ).mb_str() << '"' <<
  837. ">\n";
  838. NestedSpace( nestLevel + 1, os ) <<
  839. "<boundingBox" << m_BoundaryBox.m_Pos << m_BoundaryBox.m_Size << "/>\n";
  840. NestedSpace( nestLevel + 1, os ) << "<orientation tenths=\"" << m_Orient
  841. << "\"/>\n";
  842. EDA_ITEM* p;
  843. NestedSpace( nestLevel + 1, os ) << "<mpads>\n";
  844. p = m_Pads;
  845. for( ; p; p = p->Next() )
  846. p->Show( nestLevel + 2, os );
  847. NestedSpace( nestLevel + 1, os ) << "</mpads>\n";
  848. NestedSpace( nestLevel + 1, os ) << "<mdrawings>\n";
  849. p = m_Drawings;
  850. for( ; p; p = p->Next() )
  851. p->Show( nestLevel + 2, os );
  852. NestedSpace( nestLevel + 1, os ) << "</mdrawings>\n";
  853. p = m_Son;
  854. for( ; p; p = p->Next() )
  855. {
  856. p->Show( nestLevel + 1, os );
  857. }
  858. NestedSpace( nestLevel, os ) << "</" << GetClass().Lower().mb_str()
  859. << ">\n";
  860. }
  861. #endif