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.

534 lines
16 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
17 years ago
17 years ago
17 years ago
  1. /*****************************/
  2. /* gen_modules_placefile.cpp */
  3. /*****************************/
  4. /*
  5. * 1 - create ascii files for automatic placement of smd components
  6. * 2 - create a module report (pos and module descr) (ascii file)
  7. */
  8. #include "fctsys.h"
  9. #include "common.h"
  10. #include "confirm.h"
  11. #include "kicad_string.h"
  12. #include "gestfich.h"
  13. #include "pcbnew.h"
  14. #include "wxPcbStruct.h"
  15. #include "trigo.h"
  16. #include "appl_wxstruct.h"
  17. #include "build_version.h"
  18. class LIST_MOD /* Can list the elements of useful modules. */
  19. {
  20. public:
  21. MODULE* m_Module;
  22. const wxChar* m_Reference;
  23. const wxChar* m_Value;
  24. };
  25. static wxPoint File_Place_Offset; /* Offset coordinates for generated file. */
  26. static void WriteDrawSegmentPcb( DRAWSEGMENT* PtDrawSegment, FILE* rptfile );
  27. /* Sort function use by GenereModulesPosition() */
  28. static int ListeModCmp( const void* o1, const void* o2 )
  29. {
  30. LIST_MOD* ref = (LIST_MOD*) o1;
  31. LIST_MOD* cmp = (LIST_MOD*) o2;
  32. return StrLenNumCmp( ref->m_Reference, cmp->m_Reference, 16 );
  33. }
  34. #if defined(DEBUG)
  35. /**
  36. * Function HasNonSMDPins
  37. * returns true if the given module has any non smd pins, such as through hole
  38. * and therefore cannot be placed automatically.
  39. */
  40. static bool HasNonSMDPins( MODULE* aModule )
  41. {
  42. D_PAD* pad;
  43. for( pad = aModule->m_Pads; pad; pad = pad->Next() )
  44. {
  45. if( pad->m_Attribut != PAD_SMD )
  46. return true;
  47. }
  48. return false;
  49. }
  50. #endif
  51. /* Generate the module positions, used component placement.
  52. */
  53. void WinEDA_PcbFrame::GenModulesPosition( wxCommandEvent& event )
  54. {
  55. bool doBoardBack = false;
  56. MODULE* module;
  57. LIST_MOD* Liste = 0;
  58. char line[1024];
  59. char Buff[80];
  60. wxFileName fnFront;
  61. wxFileName fnBack;
  62. wxString msg;
  63. wxString frontLayerName;
  64. wxString backLayerName;
  65. wxString Title;
  66. FILE* fpFront = 0;
  67. FILE* fpBack = 0;
  68. bool switchedLocale = false;
  69. /* Calculate conversion scales. */
  70. double conv_unit = 0.0001; /* unites = INCHES */
  71. // if(IF_DRILL_METRIC) conv_unit = 0.000254; /* unites = mm */
  72. File_Place_Offset = m_Auxiliary_Axis_Position;
  73. /* Calculating the number of useful modules (CMS attribute, not VIRTUAL) */
  74. int moduleCount = 0;
  75. for( module = GetBoard()->m_Modules; module; module = module->Next() )
  76. {
  77. if( module->m_Attributs & MOD_VIRTUAL )
  78. {
  79. D( printf( "skipping module %s because it's virtual\n",
  80. CONV_TO_UTF8( module->GetReference() ) );)
  81. continue;
  82. }
  83. if( ( module->m_Attributs & MOD_CMS ) == 0 )
  84. {
  85. #if 1 && defined(DEBUG) // enable this code to fix a bunch of mis-labeled modules:
  86. if( !HasNonSMDPins( module ) )
  87. {
  88. // all module's pins are SMD, mark the part for pick and place
  89. module->m_Attributs |= MOD_CMS;
  90. }
  91. else
  92. {
  93. printf( "skipping %s because its attribute is not CMS and it has non SMD pins\n",
  94. CONV_TO_UTF8(module->GetReference()) );
  95. continue;
  96. }
  97. #else
  98. continue;
  99. #endif
  100. }
  101. if( module->GetLayer() == LAYER_N_BACK )
  102. doBoardBack = true;
  103. moduleCount++;
  104. }
  105. if( moduleCount == 0 )
  106. {
  107. DisplayError( this, _( "No modules for automated placement." ) );
  108. return;
  109. }
  110. fnFront = GetScreen()->m_FileName;
  111. frontLayerName = GetBoard()->GetLayerName( LAYER_N_FRONT );
  112. fnFront.SetName( fnFront.GetName() + frontLayerName );
  113. fnFront.SetExt( wxT( "pos") );
  114. fpFront = wxFopen( fnFront.GetFullPath(), wxT( "wt" ) );
  115. if( fpFront == 0 )
  116. {
  117. msg = _( "Unable to create " ) + fnFront.GetFullPath();
  118. DisplayError( this, msg );
  119. goto exit;
  120. }
  121. if( doBoardBack )
  122. {
  123. fnBack = GetScreen()->m_FileName;
  124. backLayerName = GetBoard()->GetLayerName( LAYER_N_BACK );
  125. fnBack.SetName( fnBack.GetName() + backLayerName );
  126. fnBack.SetExt( wxT( "pos" ) );
  127. fpBack = wxFopen( fnBack.GetFullPath(), wxT( "wt" ) );
  128. if( fpBack == 0 )
  129. {
  130. msg = _( "Unable to create " ) + fnBack.GetFullPath();
  131. DisplayError( this, msg );
  132. goto exit;
  133. }
  134. }
  135. // Switch the locale to standard C (needed to print floating point
  136. // numbers like 1.3)
  137. SetLocaleTo_C_standard( );
  138. switchedLocale = true;
  139. /* Display results */
  140. MsgPanel->EraseMsgBox();
  141. Affiche_1_Parametre( this, 0, _( "Component side place file:" ),
  142. fnFront.GetFullPath(), BLUE );
  143. if( doBoardBack )
  144. Affiche_1_Parametre( this, 32, _( "Copper side place file:" ),
  145. fnBack.GetFullPath(), BLUE );
  146. msg.Empty(); msg << moduleCount;
  147. Affiche_1_Parametre( this, 65, _( "Module count" ), msg, RED );
  148. /* Sort the list of modules by alphabetical order */
  149. Liste = (LIST_MOD*) MyZMalloc( moduleCount * sizeof(LIST_MOD) );
  150. module = GetBoard()->m_Modules;
  151. for( int ii = 0; module; module = module->Next() )
  152. {
  153. if( module->m_Attributs & MOD_VIRTUAL )
  154. continue;
  155. if( (module->m_Attributs & MOD_CMS) == 0 )
  156. continue;
  157. Liste[ii].m_Module = module;
  158. Liste[ii].m_Reference = module->m_Reference->m_Text;
  159. Liste[ii].m_Value = module->m_Value->m_Text;
  160. ii++;
  161. }
  162. qsort( Liste, moduleCount, sizeof(LIST_MOD), ListeModCmp );
  163. /* Generation header file comments. */
  164. sprintf( line, "### Module positions - created on %s ###\n",
  165. DateAndTime( Buff ) );
  166. fputs( line, fpFront );
  167. if( doBoardBack )
  168. fputs( line, fpBack );
  169. Title = wxGetApp().GetAppName() + wxT( " " ) + GetBuildVersion();
  170. sprintf( line, "### Printed by PcbNew version %s\n", CONV_TO_UTF8( Title ) );
  171. fputs( line, fpFront );
  172. if( doBoardBack )
  173. fputs( line, fpBack );
  174. sprintf( line, "## Unit = inches, Angle = deg.\n" );
  175. fputs( line, fpFront );
  176. if( doBoardBack )
  177. fputs( line, fpBack );
  178. sprintf( line, "## Side : %s\n", CONV_TO_UTF8( frontLayerName ) );
  179. fputs( line, fpFront );
  180. if( doBoardBack )
  181. {
  182. sprintf( line, "## Side : %s\n", CONV_TO_UTF8( backLayerName ) );
  183. fputs( line, fpBack );
  184. }
  185. sprintf( line,
  186. "# Ref Val PosX PosY Rot Side\n" );
  187. fputs( line, fpFront );
  188. if( doBoardBack )
  189. fputs( line, fpBack );
  190. for( int ii = 0; ii < moduleCount; ii++ )
  191. {
  192. wxPoint module_pos;
  193. wxString ref = Liste[ii].m_Reference;
  194. wxString val = Liste[ii].m_Value;
  195. sprintf( line, "%-8.8s %-16.16s ", CONV_TO_UTF8( ref ),
  196. CONV_TO_UTF8( val ) );
  197. module_pos = Liste[ii].m_Module->m_Pos;
  198. module_pos.x -= File_Place_Offset.x;
  199. module_pos.y -= File_Place_Offset.y;
  200. char* text = line + strlen( line );
  201. sprintf( text, " %9.4f %9.4f %8.1f ",
  202. module_pos.x * conv_unit,
  203. module_pos.y * conv_unit,
  204. double(Liste[ii].m_Module->m_Orient) / 10 );
  205. int layer = Liste[ii].m_Module->GetLayer();
  206. wxASSERT( layer==LAYER_N_FRONT || layer==LAYER_N_BACK );
  207. if( layer == LAYER_N_FRONT )
  208. {
  209. strcat( line, CONV_TO_UTF8( frontLayerName ) );
  210. strcat( line, "\n" );
  211. fputs( line, fpFront );
  212. }
  213. else if( layer == LAYER_N_BACK )
  214. {
  215. strcat( line, CONV_TO_UTF8( backLayerName ) );
  216. strcat( line, "\n" );
  217. fputs( line, fpBack );
  218. }
  219. }
  220. /* Generate EOF. */
  221. fputs( "## End\n", fpFront );
  222. if( doBoardBack )
  223. fputs( "## End\n", fpBack );
  224. msg = frontLayerName + wxT( " File: " ) + fnFront.GetFullPath();
  225. if( doBoardBack )
  226. msg += wxT("\n\n") + backLayerName + wxT( " File: " ) +
  227. fnBack.GetFullPath();
  228. DisplayInfoMessage( this, msg );
  229. exit: // the only safe way out of here, no returns please.
  230. if( Liste )
  231. MyFree( Liste );
  232. if( switchedLocale )
  233. SetLocaleTo_Default( ); // revert to the current locale
  234. if( fpFront )
  235. fclose( fpFront );
  236. if( fpBack )
  237. fclose( fpBack );
  238. }
  239. /* Print a module report.
  240. */
  241. void WinEDA_PcbFrame::GenModuleReport( wxCommandEvent& event )
  242. {
  243. double conv_unit;
  244. MODULE* Module;
  245. D_PAD* pad;
  246. char line[1024], Buff[80];
  247. wxFileName fn;
  248. wxString fnFront, msg;
  249. FILE* rptfile;
  250. wxPoint module_pos;
  251. conv_unit = 0.0001; /* unites = INCHES */
  252. // if(IF_DRILL_METRIC) conv_unit = 0.000254; /* unites = mm */
  253. File_Place_Offset = wxPoint( 0, 0 );
  254. fn = GetScreen()->m_FileName;
  255. fn.SetExt( wxT( "rpt" ) );
  256. rptfile = wxFopen( fn.GetFullPath(), wxT( "wt" ) );
  257. if( rptfile == NULL )
  258. {
  259. msg = _( "Unable to create " ) + fn.GetFullPath();
  260. DisplayError( this, msg );
  261. return;
  262. }
  263. // Switch the locale to standard C (needed to print floating point
  264. // numbers like 1.3)
  265. SetLocaleTo_C_standard( );
  266. /* Generate header file comments.) */
  267. sprintf( line, "## Module report - date %s\n", DateAndTime( Buff ) );
  268. fputs( line, rptfile );
  269. wxString Title = wxGetApp().GetAppName() + wxT( " " ) + GetBuildVersion();
  270. sprintf( line, "## Created by PcbNew version %s\n", CONV_TO_UTF8( Title ) );
  271. fputs( line, rptfile );
  272. fputs( "## Unit = inches, Angle = deg.\n", rptfile );
  273. fputs( "##\n", rptfile );
  274. fputs( "\n$BeginDESCRIPTION\n", rptfile );
  275. GetBoard()->ComputeBoundaryBox();
  276. fputs( "\n$BOARD\n", rptfile );
  277. fputs( "unit INCH\n", rptfile );
  278. sprintf( line, "upper_left_corner %9.6f %9.6f\n",
  279. GetBoard()->m_BoundaryBox.GetX() * conv_unit,
  280. GetBoard()->m_BoundaryBox.GetY() * conv_unit );
  281. fputs( line, rptfile );
  282. sprintf( line, "lower_right_corner %9.6f %9.6f\n",
  283. GetBoard()->m_BoundaryBox.GetRight() * conv_unit,
  284. GetBoard()->m_BoundaryBox.GetBottom() * conv_unit );
  285. fputs( line, rptfile );
  286. fputs( "$EndBOARD\n\n", rptfile );
  287. Module = (MODULE*) GetBoard()->m_Modules;
  288. for( ; Module != NULL; Module = Module->Next() )
  289. {
  290. sprintf( line, "$MODULE \"%s\"\n",
  291. CONV_TO_UTF8( Module->m_Reference->m_Text ) );
  292. fputs( line, rptfile );
  293. sprintf( line, "reference \"%s\"\n",
  294. CONV_TO_UTF8( Module->m_Reference->m_Text ) );
  295. fputs( line, rptfile );
  296. sprintf( line, "value \"%s\"\n",
  297. CONV_TO_UTF8( Module->m_Value->m_Text ) );
  298. fputs( line, rptfile );
  299. sprintf( line, "footprint \"%s\"\n", CONV_TO_UTF8( Module->m_LibRef ) );
  300. fputs( line, rptfile );
  301. msg = wxT( "attribut" );
  302. if( Module->m_Attributs & MOD_VIRTUAL )
  303. msg += wxT( " virtual" );
  304. if( Module->m_Attributs & MOD_CMS )
  305. msg += wxT( " smd" );
  306. if( ( Module->m_Attributs & (MOD_VIRTUAL | MOD_CMS) ) == 0 )
  307. msg += wxT( " none" );
  308. msg += wxT( "\n" );
  309. fputs( CONV_TO_UTF8( msg ), rptfile );
  310. module_pos = Module->m_Pos;
  311. module_pos.x -= File_Place_Offset.x;
  312. module_pos.y -= File_Place_Offset.y;
  313. sprintf( line, "position %9.6f %9.6f\n",
  314. module_pos.x * conv_unit,
  315. module_pos.y * conv_unit );
  316. fputs( line, rptfile );
  317. sprintf( line, "orientation %.2f\n", (double) Module->m_Orient / 10 );
  318. if( Module->GetLayer() == LAYER_N_FRONT )
  319. strcat( line, "layer component\n" );
  320. else if( Module->GetLayer() == LAYER_N_BACK )
  321. strcat( line, "layer copper\n" );
  322. else
  323. strcat( line, "layer other\n" );
  324. fputs( line, rptfile );
  325. Module->Write_3D_Descr( rptfile );
  326. for( pad = Module->m_Pads; pad != NULL; pad = pad->Next() )
  327. {
  328. fprintf( rptfile, "$PAD \"%.4s\"\n", pad->m_Padname );
  329. sprintf( line, "position %9.6f %9.6f\n",
  330. pad->m_Pos0.x * conv_unit,
  331. pad->m_Pos0.y * conv_unit );
  332. fputs( line, rptfile );
  333. sprintf( line, "size %9.6f %9.6f\n",
  334. pad->m_Size.x * conv_unit,
  335. pad->m_Size.y * conv_unit );
  336. fputs( line, rptfile );
  337. sprintf( line, "drill %9.6f\n", pad->m_Drill.x * conv_unit );
  338. fputs( line, rptfile );
  339. sprintf( line, "shape_offset %9.6f %9.6f\n",
  340. pad->m_Offset.x * conv_unit,
  341. pad->m_Offset.y * conv_unit );
  342. fputs( line, rptfile );
  343. sprintf( line, "orientation %.2f\n",
  344. double(pad->m_Orient - Module->m_Orient) / 10 );
  345. fputs( line, rptfile );
  346. const char* shape_name[6] =
  347. { "??? ", "Circ", "Rect", "Oval", "trap", "spec" };
  348. sprintf( line, "Shape %s\n", shape_name[pad->m_PadShape] );
  349. fputs( line, rptfile );
  350. int layer = 0;
  351. if( pad->m_Masque_Layer & LAYER_BACK )
  352. layer = 1;
  353. if( pad->m_Masque_Layer & LAYER_FRONT )
  354. layer |= 2;
  355. const char* layer_name[4] = { "??? ", "copper", "component", "all" };
  356. sprintf( line, "Layer %s\n", layer_name[layer] );
  357. fputs( line, rptfile );
  358. fprintf( rptfile, "$EndPAD\n" );
  359. }
  360. fprintf( rptfile, "$EndMODULE %s\n\n",
  361. CONV_TO_UTF8(Module->m_Reference->m_Text ) );
  362. }
  363. /* Write board Edges */
  364. EDA_BaseStruct* PtStruct;
  365. for( PtStruct = GetBoard()->m_Drawings; PtStruct != NULL; PtStruct = PtStruct->Next() )
  366. {
  367. if( PtStruct->Type() != TYPE_DRAWSEGMENT )
  368. continue;
  369. if( ( (DRAWSEGMENT*) PtStruct )->GetLayer() != EDGE_N )
  370. continue;
  371. WriteDrawSegmentPcb( (DRAWSEGMENT*) PtStruct, rptfile );
  372. }
  373. /* Generate EOF. */
  374. fputs( "$EndDESCRIPTION\n", rptfile );
  375. fclose( rptfile );
  376. SetLocaleTo_Default( ); // revert to the current locale
  377. }
  378. /* Output to rpt file a segment type from the PCB drawing.
  379. * The contours are of different types:
  380. * Segment
  381. * Circle
  382. * Arc
  383. */
  384. void WriteDrawSegmentPcb( DRAWSEGMENT* PtDrawSegment, FILE* rptfile )
  385. {
  386. double conv_unit, ux0, uy0, dx, dy;
  387. double rayon, width;
  388. char line[1024];
  389. conv_unit = 0.0001; /* units = INCHES */
  390. ux0 = PtDrawSegment->m_Start.x * conv_unit;
  391. uy0 = PtDrawSegment->m_Start.y * conv_unit;
  392. dx = PtDrawSegment->m_End.x * conv_unit;
  393. dy = PtDrawSegment->m_End.y * conv_unit;
  394. width = PtDrawSegment->m_Width * conv_unit;
  395. switch( PtDrawSegment->m_Shape )
  396. {
  397. case S_CIRCLE:
  398. rayon = hypot( dx - ux0, dy - uy0 );
  399. fprintf( rptfile, "$CIRCLE \n" );
  400. fprintf( rptfile, "centre %.6lf %.6lf\n", ux0, uy0 );
  401. fprintf( rptfile, "radius %.6lf\n", rayon );
  402. fprintf( rptfile, "width %.6lf\n", width );
  403. fprintf( rptfile, "$EndCIRCLE \n" );
  404. break;
  405. case S_ARC:
  406. {
  407. int endx = PtDrawSegment->m_End.x, endy = PtDrawSegment->m_End.y;
  408. rayon = hypot( dx - ux0, dy - uy0 );
  409. RotatePoint( &endx,
  410. &endy,
  411. PtDrawSegment->m_Start.x,
  412. PtDrawSegment->m_Start.y,
  413. PtDrawSegment->m_Angle );
  414. fprintf( rptfile, "$ARC \n" );
  415. fprintf( rptfile, "centre %.6lf %.6lf\n", ux0, uy0 );
  416. fprintf( rptfile, "start %.6lf %.6lf\n",
  417. endx * conv_unit, endy * conv_unit );
  418. fprintf( rptfile, "end %.6lf %.6lf\n", dx, dy );
  419. fprintf( rptfile, "width %.6lf\n", width );
  420. fprintf( rptfile, "$EndARC \n" );
  421. }
  422. break;
  423. default:
  424. sprintf( line, "$LINE \n" );
  425. fputs( line, rptfile );
  426. fprintf( rptfile, "start %.6lf %.6lf\n", ux0, uy0 );
  427. fprintf( rptfile, "end %.6lf %.6lf\n", dx, dy );
  428. fprintf( rptfile, "width %.6lf\n", width );
  429. fprintf( rptfile, "$EndLINE \n" );
  430. break;
  431. }
  432. }