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.

899 lines
29 KiB

17 years ago
17 years ago
16 years ago
16 years ago
16 years ago
16 years ago
17 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
18 years ago
16 years ago
16 years ago
16 years ago
16 years ago
18 years ago
18 years ago
16 years ago
18 years ago
16 years ago
16 years ago
16 years ago
18 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
18 years ago
18 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
17 years ago
16 years ago
17 years ago
16 years ago
16 years ago
17 years ago
16 years ago
17 years ago
16 years ago
16 years ago
17 years ago
17 years ago
16 years ago
16 years ago
18 years ago
16 years ago
18 years ago
16 years ago
16 years ago
16 years ago
16 years ago
  1. /************************************************/
  2. /* export_gencad.cpp - export GenCAD 1.4 format */
  3. /************************************************/
  4. #include "fctsys.h"
  5. #include "common.h"
  6. #include "class_drawpanel.h"
  7. #include "confirm.h"
  8. #include "gestfich.h"
  9. #include "appl_wxstruct.h"
  10. #include "pcbnew.h"
  11. #include "wxPcbStruct.h"
  12. #include "trigo.h"
  13. bool CreateHeaderInfoData( FILE* file, WinEDA_PcbFrame* frame );
  14. static void CreateTracksInfoData( FILE* file, BOARD* pcb );
  15. static void CreateBoardSection( FILE* file, BOARD* pcb );
  16. static void CreateComponentsSection( FILE* file, BOARD* pcb );
  17. static void CreateDevicesSection( FILE* file, BOARD* pcb );
  18. static void CreateRoutesSection( FILE* file, BOARD* pcb );
  19. static void CreateSignalsSection( FILE* file, BOARD* pcb );
  20. static void CreateShapesSection( FILE* file, BOARD* pcb );
  21. static void CreatePadsShapesSection( FILE* file, BOARD* pcb );
  22. static void CreatePadsStacksSection( FILE* file, BOARD* pcb );
  23. static void FootprintWriteShape( FILE* File, MODULE* module );
  24. // layer name for Gencad export
  25. static const wxString GenCAD_Layer_Name[32] =
  26. {
  27. wxT( "BOTTOM" ), wxT( "INNER1" ), wxT( "INNER2" ),
  28. wxT( "INNER3" ), wxT( "INNER4" ), wxT( "INNER5" ),
  29. wxT( "INNER6" ), wxT( "INNER7" ), wxT( "INNER8" ),
  30. wxT( "INNER9" ), wxT( "INNER10" ), wxT( "INNER11" ),
  31. wxT( "INNER12" ), wxT( "INNER13" ), wxT( "INNER14" ),
  32. wxT( "TOP" ), wxT( "adhecu" ), wxT( "adhecmp" ),
  33. wxT( "SOLDERPASTE_BOTTOM" ), wxT( "SOLDERPASTE_TOP" ),
  34. wxT( "SILKSCREEN_BOTTOM" ), wxT( "SILKSCREEN_TOP" ),
  35. wxT( "SOLDERMASK_BOTTOM" ), wxT( "SOLDERMASK_TOP" ), wxT( "drawings" ),
  36. wxT( "comments" ), wxT( "eco1" ), wxT( "eco2" ),
  37. wxT( "edges" ), wxT( "--" ), wxT( "--" ),
  38. wxT( "--" )
  39. };
  40. int offsetX, offsetY;
  41. D_PAD* PadList;
  42. /* 2 helper functions to calculate coordinates of modules in gencad values (
  43. * GenCAD Y axis from bottom to top)
  44. */
  45. static int mapXto( int x )
  46. {
  47. return x - offsetX;
  48. }
  49. static int mapYto( int y )
  50. {
  51. return offsetY - y;
  52. }
  53. /*
  54. * Creates an Export file (format GenCAD 1.4) from the current board.
  55. */
  56. void WinEDA_PcbFrame::ExportToGenCAD( wxCommandEvent& event )
  57. {
  58. wxFileName fn = GetScreen()->m_FileName;
  59. wxString msg, ext, wildcard;
  60. FILE* file;
  61. ext = wxT( "cad" );
  62. wildcard = _( "GenCAD 1.4 board files (.cad)|*.cad" );
  63. fn.SetExt( ext );
  64. wxFileDialog dlg( this, _( "Save GenCAD Board File" ), wxGetCwd(),
  65. fn.GetFullName(), wildcard,
  66. wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
  67. if( dlg.ShowModal() == wxID_CANCEL )
  68. return;
  69. if( ( file = wxFopen( dlg.GetPath(), wxT( "wt" ) ) ) == NULL )
  70. {
  71. msg = _( "Unable to create " ) + dlg.GetPath();
  72. DisplayError( this, msg ); return;
  73. }
  74. /* Update some board data, to ensure a reliable gencad export: */
  75. GetBoard()->ComputeBoundaryBox();
  76. offsetX = m_Auxiliary_Axis_Position.x;
  77. offsetY = m_Auxiliary_Axis_Position.y;
  78. wxClientDC dc( DrawPanel );
  79. DrawPanel->PrepareGraphicContext( &dc );
  80. Compile_Ratsnest( &dc, TRUE );
  81. /* Temporary modification of footprints that are flipped (i.e. on bottom
  82. * layer) to convert them to non flipped footprints.
  83. * This is necessary to easily export shapes to GenCAD,
  84. * that are given as normal orientation (non flipped, rotation = 0))
  85. * these changes will be undone later
  86. */
  87. MODULE* module;
  88. for( module = GetBoard()->m_Modules; module != NULL; module = module->Next() )
  89. {
  90. module->flag = 0;
  91. if( module->GetLayer() == LAYER_N_BACK )
  92. {
  93. module->Flip( module->m_Pos );
  94. module->flag = 1;
  95. }
  96. }
  97. // Create file header:
  98. CreateHeaderInfoData( file, this );
  99. CreateBoardSection( file, GetBoard() );
  100. /* Create TRACKS list
  101. * This is the section $TRACK) (track width sizes) */
  102. CreateTracksInfoData( file, GetBoard() );
  103. /* Create the shapes list
  104. * (shapes of pads and footprints */
  105. CreatePadsShapesSection( file, GetBoard() ); /* Must be called
  106. * before
  107. * CreatePadsStacksSection
  108. * and
  109. * CreateShapesSection()
  110. */
  111. CreatePadsStacksSection( file, GetBoard() );
  112. CreateShapesSection( file, GetBoard() );
  113. CreateDevicesSection( file, GetBoard() );
  114. CreateComponentsSection( file, GetBoard() );
  115. /* Create the list of Nets: */
  116. CreateSignalsSection( file, GetBoard() );
  117. // Creates the Routes section (i.e. the list of board tracks)
  118. CreateRoutesSection( file, GetBoard() );
  119. fclose( file );
  120. /* Undo the footprints modifications (flipped footprints) */
  121. for( module = GetBoard()->m_Modules; module != NULL; module = module->Next() )
  122. {
  123. if( module->flag )
  124. {
  125. module->Flip( module->m_Pos );
  126. module->flag = 0;
  127. }
  128. }
  129. }
  130. static int Pad_list_Sort_by_Shapes( const void* refptr, const void* objptr )
  131. {
  132. const D_PAD* padref = *(D_PAD**) refptr;
  133. const D_PAD* padcmp = *(D_PAD**) objptr;
  134. return D_PAD::Compare( padref, padcmp );
  135. }
  136. /* Creates the pads shapes list ( 1 shape per pad )
  137. * Uses .GetSubRatsnest member of class D_PAD, to handle the shape id (value 1
  138. * ..n) for pads shapes PAD1 to PADn
  139. *
  140. * The PADS section is used to describe the shape of all the pads used on the
  141. * printed circuit board. The PADS section must be included, even if only a
  142. * default pad is described and used for all pads.
  143. * The keywords used in the PADS section are:
  144. * $PADS
  145. * PAD <pad_name> <pad_type> <drill_size>
  146. * LINE <line_ref>
  147. * ARC <arc_ref>
  148. * CIRCLE <circle_ref>
  149. * RECTANGLE <rectangle_ref>
  150. * ATTRIBUTE <attrib_ref>
  151. * $ENDPADS
  152. * $PADS and $ENDPADS mark the PADS section of the GenCAD file. Each pad
  153. * description must start with a PAD keyword.
  154. * The layer in which a pad lies is defined in the SHAPE section of the GenCAD
  155. * specification.
  156. * The pad is always placed on a shape at the pad origin, or in a pad stack at
  157. * the pad stack origin.
  158. */
  159. void CreatePadsShapesSection( FILE* file, BOARD* pcb )
  160. {
  161. std::vector<D_PAD*> pads;
  162. const char* pad_type;
  163. fputs( "$PADS\n", file );
  164. if( pcb->GetPadsCount() > 0 )
  165. {
  166. pads.insert( pads.end(),
  167. pcb->m_NetInfo->m_PadsFullList.begin(),
  168. pcb->m_NetInfo->m_PadsFullList.end() );
  169. qsort( &pads[0], pcb->GetPadsCount(), sizeof( D_PAD* ),
  170. Pad_list_Sort_by_Shapes );
  171. }
  172. D_PAD* old_pad = NULL;
  173. int pad_name_number = 0;
  174. for( unsigned i = 0; i<pads.size(); ++i )
  175. {
  176. D_PAD* pad = pads[i];
  177. pad->SetSubRatsnest( pad_name_number );
  178. if( old_pad && 0==D_PAD::Compare( old_pad, pad ) )
  179. continue; // already created
  180. old_pad = pad;
  181. pad_name_number++;
  182. pad->SetSubRatsnest( pad_name_number );
  183. fprintf( file, "PAD PAD%d", pad->GetSubRatsnest() );
  184. int dx = pad->m_Size.x / 2;
  185. int dy = pad->m_Size.y / 2;
  186. switch( pad->m_PadShape )
  187. {
  188. default:
  189. case PAD_CIRCLE:
  190. pad_type = "ROUND";
  191. fprintf( file, " %s %d\n", pad_type, pad->m_Drill.x );
  192. fprintf( file, "CIRCLE %d %d %d\n",
  193. pad->m_Offset.x, -pad->m_Offset.y, dx );
  194. break;
  195. case PAD_RECT:
  196. pad_type = "RECTANGULAR";
  197. fprintf( file, " %s %d\n", pad_type, pad->m_Drill.x );
  198. fprintf( file, "RECTANGLE %d %d %d %d\n",
  199. pad->m_Offset.x - dx, -(pad->m_Offset.y - dy),
  200. pad->m_Offset.x + dx, -(pad->m_Offset.y + dy) );
  201. break;
  202. case PAD_OVAL: /* Create outline by 2 lines and 2 arcs */
  203. {
  204. pad_type = "FINGER";
  205. fprintf( file, " %s %d\n", pad_type, pad->m_Drill.x );
  206. int dr = dx - dy;
  207. if( dr >= 0 ) // Horizontal oval
  208. {
  209. int rayon = dy;
  210. fprintf( file, "LINE %d %d %d %d\n",
  211. -dr + pad->m_Offset.x, -pad->m_Offset.y - rayon,
  212. dr + pad->m_Offset.x, -pad->m_Offset.y - rayon );
  213. fprintf( file, "ARC %d %d %d %d %d %d\n",
  214. dr + pad->m_Offset.x, -pad->m_Offset.y - rayon,
  215. dr + pad->m_Offset.x, -pad->m_Offset.y + rayon,
  216. dr + pad->m_Offset.x, -pad->m_Offset.y );
  217. fprintf( file, "LINE %d %d %d %d\n",
  218. dr + pad->m_Offset.x, -pad->m_Offset.y + rayon,
  219. -dr + pad->m_Offset.x, -pad->m_Offset.y + rayon );
  220. fprintf( file, "ARC %d %d %d %d %d %d\n",
  221. -dr + pad->m_Offset.x, -pad->m_Offset.y + rayon,
  222. -dr + pad->m_Offset.x, -pad->m_Offset.y - rayon,
  223. -dr + pad->m_Offset.x, -pad->m_Offset.y );
  224. }
  225. else // Vertical oval
  226. {
  227. dr = -dr;
  228. int rayon = dx;
  229. fprintf( file, "LINE %d %d %d %d\n",
  230. -rayon + pad->m_Offset.x, -pad->m_Offset.y - dr,
  231. -rayon + pad->m_Offset.x, -pad->m_Offset.y + dr );
  232. fprintf( file, "ARC %d %d %d %d %d %d\n",
  233. -rayon + pad->m_Offset.x, -pad->m_Offset.y + dr,
  234. rayon + pad->m_Offset.x, -pad->m_Offset.y + dr,
  235. pad->m_Offset.x, -pad->m_Offset.y + dr );
  236. fprintf( file, "LINE %d %d %d %d\n",
  237. rayon + pad->m_Offset.x, -pad->m_Offset.y + dr,
  238. rayon + pad->m_Offset.x, -pad->m_Offset.y - dr );
  239. fprintf( file, "ARC %d %d %d %d %d %d\n",
  240. rayon + pad->m_Offset.x, -pad->m_Offset.y - dr,
  241. -rayon + pad->m_Offset.x, -pad->m_Offset.y - dr,
  242. pad->m_Offset.x, -pad->m_Offset.y - dr );
  243. }
  244. break;
  245. }
  246. case PAD_TRAPEZOID:
  247. pad_type = "POLYGON";
  248. break;
  249. }
  250. }
  251. fputs( "$ENDPADS\n\n", file );
  252. }
  253. /*The PADSTACKS section is optional, and is used to describe how a group of
  254. * pads are
  255. * arranged. The keywords used in the PADSTACKS section are:
  256. * $PADSTACKS
  257. * PADSTACK <pad_name> <drill_size>
  258. * PAD <pad_name> <layer> <rot> <mirror>
  259. * ATTRIBUTE <attrib_ref>
  260. * $ENDPADSTACKS
  261. * $PADSTACKS and $ENDPADSTACKS mark the PADSTACKS section of the GenCAD file.
  262. */
  263. void CreatePadsStacksSection( FILE* file, BOARD* pcb )
  264. {
  265. fputs( "$PADSTACKS\n", file );
  266. fputs( "$ENDPADSTACKS\n\n", file );
  267. }
  268. /* Creates the footprint shape list.
  269. * We must use one shape for identical footprint (i.e. come from the same
  270. * footprint in lib)
  271. * But because pads shapes and positions can be easily modified on board,
  272. * a shape is created by footprint found.
  273. * (todo : compare footprints shapes and creates only one shape for all
  274. * footprints found having the same shape)
  275. * The shape is always given in orientation 0, position 0 not flipped
  276. *
  277. * Syntax:
  278. * $SHAPES
  279. * SHAPE <shape_name>
  280. * INSERT <string> here <string> = "TH"
  281. * shape_descr (line, arc ..)
  282. * PIN <pin_name> <pad_name> <x_y_ref> <layer> <rot> <mirror>
  283. *
  284. * SHAPE <shape_name>
  285. * ..
  286. * $ENDSHAPES
  287. */
  288. void CreateShapesSection( FILE* file, BOARD* pcb )
  289. {
  290. MODULE* module;
  291. D_PAD* pad;
  292. const char* layer;
  293. int orient;
  294. wxString pinname;
  295. const char* mirror = "0";
  296. fputs( "$SHAPES\n", file );
  297. for( module = pcb->m_Modules; module != NULL; module = module->Next() )
  298. {
  299. FootprintWriteShape( file, module );
  300. for( pad = module->m_Pads; pad != NULL; pad = pad->Next() )
  301. {
  302. layer = "ALL";
  303. if( ( pad->m_Masque_Layer & ALL_CU_LAYERS ) == CUIVRE_LAYER )
  304. {
  305. if( module->GetLayer() == LAYER_N_FRONT )
  306. layer = "BOTTOM";
  307. else
  308. layer = "TOP";
  309. }
  310. else if( ( pad->m_Masque_Layer & ALL_CU_LAYERS ) == CMP_LAYER )
  311. {
  312. if( module->GetLayer() == LAYER_N_FRONT )
  313. layer = "TOP";
  314. else
  315. layer = "BOTTOM";
  316. }
  317. pad->ReturnStringPadName( pinname );
  318. if( pinname.IsEmpty() )
  319. pinname = wxT( "noname" );
  320. orient = pad->m_Orient - module->m_Orient;
  321. NORMALIZE_ANGLE_POS( orient );
  322. fprintf( file, "PIN %s PAD%d %d %d %s %d %s",
  323. CONV_TO_UTF8( pinname ), pad->GetSubRatsnest(),
  324. pad->m_Pos0.x, -pad->m_Pos0.y,
  325. layer, orient / 10, mirror );
  326. if( orient % 10 )
  327. fprintf( file, " .%d", orient % 10 );
  328. fprintf( file, "\n" );
  329. }
  330. }
  331. fputs( "$ENDSHAPES\n\n", file );
  332. }
  333. /* Creates the section $COMPONENTS (Footprints placement)
  334. * When a footprint is on bottom side of the board::
  335. * shapes are given with option "FLIP" and "MIRRORX".
  336. * - But shapes remain given like component not mirrored and not flipped
  337. * - orientation is given like if where not mirrored and not flipped.
  338. */
  339. void CreateComponentsSection( FILE* file, BOARD* pcb )
  340. {
  341. MODULE* module = pcb->m_Modules;
  342. TEXTE_MODULE* PtTexte;
  343. const char* mirror;
  344. const char* flip;
  345. int ii;
  346. fputs( "$COMPONENTS\n", file );
  347. for( ; module != NULL; module = module->Next() )
  348. {
  349. int orient = module->m_Orient;
  350. if( module->flag )
  351. {
  352. mirror = "MIRRORX"; // Mirrored relative to X axis
  353. flip = "FLIP"; // Normal shape description ( gencad
  354. // viewer must show it flipped and
  355. // mirrored)
  356. NEGATE_AND_NORMALIZE_ANGLE_POS( orient );
  357. }
  358. else
  359. {
  360. mirror = "0";
  361. flip = "0";
  362. }
  363. fprintf( file, "COMPONENT %s\n",
  364. CONV_TO_UTF8( module->m_Reference->m_Text ) );
  365. fprintf( file, "DEVICE %s\n",
  366. CONV_TO_UTF8( module->m_Reference->m_Text ) );
  367. fprintf( file, "PLACE %d %d\n", mapXto( module->m_Pos.x ),
  368. mapYto( module->m_Pos.y ) );
  369. fprintf( file, "LAYER %s\n", (module->flag) ? "BOTTOM" : "TOP" );
  370. fprintf( file, "ROTATION %d", orient / 10 );
  371. if( orient % 10 )
  372. fprintf( file, ".%d", orient % 10 );
  373. fputs( "\n", file );
  374. fprintf( file, "SHAPE %s %s %s\n",
  375. CONV_TO_UTF8( module->m_Reference->m_Text ), mirror, flip );
  376. /* creates texts (ref and value) */
  377. PtTexte = module->m_Reference;
  378. for( ii = 0; ii < 2; ii++ )
  379. {
  380. int orient = PtTexte->m_Orient;
  381. wxString layer = GenCAD_Layer_Name[SILKSCREEN_N_CMP];
  382. fprintf( file, "TEXT %d %d %d %d.%d %s %s \"%s\"",
  383. PtTexte->m_Pos0.x, -PtTexte->m_Pos0.y,
  384. PtTexte->m_Size.x,
  385. orient / 10, orient % 10,
  386. mirror,
  387. CONV_TO_UTF8( layer ),
  388. CONV_TO_UTF8( PtTexte->m_Text )
  389. );
  390. fprintf( file, " 0 0 %d %d\n",
  391. (int) ( PtTexte->m_Size.x * PtTexte->m_Text.Len() ),
  392. (int) PtTexte->m_Size.y );
  393. PtTexte = module->m_Value;
  394. }
  395. //put a comment:
  396. fprintf( file, "SHEET Part %s %s\n",
  397. CONV_TO_UTF8( module->m_Reference->m_Text ),
  398. CONV_TO_UTF8( module->m_Value->m_Text ) );
  399. }
  400. fputs( "$ENDCOMPONENTS\n\n", file );
  401. }
  402. /* Creates the list of Nets:
  403. * $SIGNALS
  404. * SIGNAL <net name>
  405. * NODE <component name> <pin name>
  406. * ...
  407. * NODE <component name> <pin name>
  408. * $ENDSIGNALS
  409. */
  410. void CreateSignalsSection( FILE* file, BOARD* pcb )
  411. {
  412. wxString msg;
  413. NETINFO_ITEM* net;
  414. D_PAD* pad;
  415. MODULE* module;
  416. int NbNoConn = 1;
  417. fputs( "$SIGNALS\n", file );
  418. for( unsigned ii = 0; ii < pcb->m_NetInfo->GetCount(); ii++ )
  419. {
  420. net = pcb->m_NetInfo->GetNetItem( ii );
  421. if( net->GetNetname() == wxEmptyString ) // dummy netlist (no
  422. // connection)
  423. {
  424. wxString msg; msg << wxT( "NoConnection" ) << NbNoConn++;
  425. net->SetNetname( msg );;
  426. }
  427. if( net->GetNet() <= 0 ) // dummy netlist (no connection)
  428. continue;
  429. msg = wxT( "SIGNAL " ) + net->GetNetname();
  430. fputs( CONV_TO_UTF8( msg ), file );
  431. fputs( "\n", file );
  432. for( module = pcb->m_Modules; module != NULL; module = module->Next() )
  433. {
  434. for( pad = module->m_Pads; pad != NULL; pad = pad->Next() )
  435. {
  436. wxString padname;
  437. if( pad->GetNet() != net->GetNet() )
  438. continue;
  439. pad->ReturnStringPadName( padname );
  440. msg.Printf( wxT( "NODE %s %.4s" ),
  441. GetChars( module->m_Reference->m_Text ),
  442. GetChars( padname ) );
  443. fputs( CONV_TO_UTF8( msg ), file );
  444. fputs( "\n", file );
  445. }
  446. }
  447. }
  448. fputs( "$ENDSIGNALS\n\n", file );
  449. }
  450. /* Creates the section $HEADER ... $ENDHEADER
  451. */
  452. bool CreateHeaderInfoData( FILE* file, WinEDA_PcbFrame* frame )
  453. {
  454. wxString msg;
  455. PCB_SCREEN* screen = (PCB_SCREEN*) ( frame->GetScreen() );
  456. fputs( "$HEADER\n", file );
  457. fputs( "GENCAD 1.4\n", file );
  458. msg = wxT( "USER " ) + wxGetApp().GetAppName() + wxT( " " ) +
  459. GetBuildVersion();
  460. fputs( CONV_TO_UTF8( msg ), file ); fputs( "\n", file );
  461. msg = wxT( "DRAWING " ) + screen->m_FileName;
  462. fputs( CONV_TO_UTF8( msg ), file ); fputs( "\n", file );
  463. msg = wxT( "REVISION " ) + screen->m_Revision + wxT( " " ) +
  464. screen->m_Date;
  465. fputs( CONV_TO_UTF8( msg ), file ); fputs( "\n", file );
  466. msg.Printf( wxT( "UNITS USER %d" ), PCB_INTERNAL_UNIT );
  467. fputs( CONV_TO_UTF8( msg ), file ); fputs( "\n", file );
  468. msg.Printf( wxT( "ORIGIN %d %d" ),
  469. mapXto( frame->m_Auxiliary_Axis_Position.x ),
  470. mapYto( frame->m_Auxiliary_Axis_Position.y ) );
  471. fputs( CONV_TO_UTF8( msg ), file ); fputs( "\n", file );
  472. fputs( "INTERTRACK 0\n", file );
  473. fputs( "$ENDHEADER\n\n", file );
  474. return TRUE;
  475. }
  476. /*
  477. * Sort function used to sort tracks segments:
  478. * items are sorted by netcode, then by width then by layer
  479. */
  480. static int Track_list_Sort_by_Netcode( const void* refptr, const void* objptr )
  481. {
  482. const TRACK* ref, * cmp;
  483. int diff;
  484. ref = *( (TRACK**) refptr );
  485. cmp = *( (TRACK**) objptr );
  486. if( ( diff = ref->GetNet() - cmp->GetNet() ) )
  487. return diff;
  488. if( ( diff = ref->m_Width - cmp->m_Width ) )
  489. return diff;
  490. if( ( diff = ref->GetLayer() - cmp->GetLayer() ) )
  491. return diff;
  492. return 0;
  493. }
  494. /* Creates the section ROUTES
  495. * that handles tracks, vias
  496. * TODO: add zones
  497. * section:
  498. * $ROUTE
  499. * ...
  500. * $ENROUTE
  501. * Track segments must be sorted by nets
  502. */
  503. void CreateRoutesSection( FILE* file, BOARD* pcb )
  504. {
  505. TRACK* track, ** tracklist;
  506. int vianum = 1;
  507. int old_netcode, old_width, old_layer;
  508. int nbitems, ii;
  509. // Count items
  510. nbitems = 0;
  511. for( track = pcb->m_Track; track != NULL; track = track->Next() )
  512. nbitems++;
  513. for( track = pcb->m_Zone; track != NULL; track = track->Next() )
  514. {
  515. if( track->Type() == TYPE_ZONE )
  516. nbitems++;
  517. }
  518. tracklist = (TRACK**) MyMalloc( (nbitems + 1) * sizeof(TRACK*) );
  519. nbitems = 0;
  520. for( track = pcb->m_Track; track != NULL; track = track->Next() )
  521. tracklist[nbitems++] = track;
  522. for( track = pcb->m_Zone; track != NULL; track = track->Next() )
  523. {
  524. if( track->Type() == TYPE_ZONE )
  525. tracklist[nbitems++] = track;
  526. }
  527. tracklist[nbitems] = NULL;
  528. qsort( tracklist, nbitems, sizeof(TRACK*), Track_list_Sort_by_Netcode );
  529. fputs( "$ROUTES\n", file );
  530. old_netcode = -1; old_width = -1; old_layer = -1;
  531. for( ii = 0; ii < nbitems; ii++ )
  532. {
  533. track = tracklist[ii];
  534. if( old_netcode != track->GetNet() )
  535. {
  536. old_netcode = track->GetNet();
  537. NETINFO_ITEM* net = pcb->FindNet( track->GetNet() );
  538. wxString netname;
  539. if( net && (net->GetNetname() != wxEmptyString) )
  540. netname = net->GetNetname();
  541. else
  542. netname = wxT( "_noname_" );
  543. fprintf( file, "ROUTE %s\n", CONV_TO_UTF8( netname ) );
  544. }
  545. if( old_width != track->m_Width )
  546. {
  547. old_width = track->m_Width;
  548. fprintf( file, "TRACK TRACK%d\n", track->m_Width );
  549. }
  550. if( (track->Type() == TYPE_TRACK) || (track->Type() == TYPE_ZONE) )
  551. {
  552. if( old_layer != track->GetLayer() )
  553. {
  554. old_layer = track->GetLayer();
  555. fprintf( file, "LAYER %s\n",
  556. CONV_TO_UTF8( GenCAD_Layer_Name[track->GetLayer() &
  557. 0x1F] ) );
  558. }
  559. fprintf( file, "LINE %d %d %d %d\n",
  560. mapXto( track->m_Start.x ), mapYto( track->m_Start.y ),
  561. mapXto( track->m_End.x ), mapYto( track->m_End.y ) );
  562. }
  563. if( track->Type() == TYPE_VIA )
  564. {
  565. fprintf( file, "VIA viapad%d %d %d ALL %d via%d\n",
  566. track->m_Width,
  567. mapXto( track->m_Start.x ), mapYto( track->m_Start.y ),
  568. track->GetDrillValue(), vianum++ );
  569. }
  570. }
  571. fputs( "$ENDROUTES\n\n", file );
  572. free( tracklist );
  573. }
  574. /* Creates the section $DEVICES
  575. * This is a list of footprints properties
  576. * ( Shapes are in section $SHAPE )
  577. */
  578. void CreateDevicesSection( FILE* file, BOARD* pcb )
  579. {
  580. MODULE* module;
  581. D_PAD* pad;
  582. fputs( "$DEVICES\n", file );
  583. for( module = pcb->m_Modules; module != NULL; module = module->Next() )
  584. {
  585. fprintf( file, "DEVICE %s\n",
  586. CONV_TO_UTF8( module->m_Reference->m_Text ) );
  587. fprintf( file, "PART %s\n", CONV_TO_UTF8( module->m_LibRef ) );
  588. fprintf( file, "TYPE %s\n", "UNKNOWN" );
  589. for( pad = module->m_Pads; pad != NULL; pad = pad->Next() )
  590. {
  591. fprintf( file, "PINDESCR %.4s", pad->m_Padname );
  592. if( pad->GetNetname() == wxEmptyString )
  593. fputs( " NoConn\n", file );
  594. else
  595. fprintf( file, " %.4s\n", pad->m_Padname );
  596. }
  597. fprintf( file, "ATTRIBUTE %s\n",
  598. CONV_TO_UTF8( module->m_Value->m_Text ) );
  599. }
  600. fputs( "$ENDDEVICES\n\n", file );
  601. }
  602. /* Creates the section $BOARD.
  603. * We output here only the board boundary box
  604. */
  605. void CreateBoardSection( FILE* file, BOARD* pcb )
  606. {
  607. fputs( "$BOARD\n", file );
  608. fprintf( file, "LINE %d %d %d %d\n",
  609. mapXto( pcb->m_BoundaryBox.m_Pos.x ),
  610. mapYto( pcb->m_BoundaryBox.m_Pos.y ),
  611. mapXto( pcb->m_BoundaryBox.GetRight() ),
  612. mapYto( pcb->m_BoundaryBox.m_Pos.y ) );
  613. fprintf( file, "LINE %d %d %d %d\n",
  614. mapXto( pcb->m_BoundaryBox.GetRight() ),
  615. mapYto( pcb->m_BoundaryBox.m_Pos.y ),
  616. mapXto( pcb->m_BoundaryBox.GetRight() ),
  617. mapYto( pcb->m_BoundaryBox.GetBottom() ) );
  618. fprintf( file, "LINE %d %d %d %d\n",
  619. mapXto( pcb->m_BoundaryBox.GetRight() ),
  620. mapYto( pcb->m_BoundaryBox.GetBottom() ),
  621. mapXto( pcb->m_BoundaryBox.m_Pos.x ),
  622. mapYto( pcb->m_BoundaryBox.GetBottom() ) );
  623. fprintf( file, "LINE %d %d %d %d\n",
  624. mapXto( pcb->m_BoundaryBox.m_Pos.x ),
  625. mapYto( pcb->m_BoundaryBox.GetBottom() ),
  626. mapXto( pcb->m_BoundaryBox.m_Pos.x ),
  627. mapYto( pcb->m_BoundaryBox.m_Pos.y ) );
  628. fputs( "$ENDBOARD\n\n", file );
  629. }
  630. /* Creates the section "$TRACKS"
  631. * This sections give the list of widths (tools) used in tracks and vias
  632. * format:
  633. * $TRACK
  634. * TRACK <name> <width>
  635. * $ENDTRACK
  636. *
  637. * Each tool name is build like this: "TRACK" + track width.
  638. * For instance for a width = 120 : name = "TRACK120".
  639. */
  640. void CreateTracksInfoData( FILE* file, BOARD* pcb )
  641. {
  642. TRACK* track;
  643. int last_width = -1;
  644. /* Find thickness used for traces. */
  645. std::vector <int> trackinfo;
  646. unsigned ii;
  647. for( track = pcb->m_Track; track != NULL; track = track->Next() )
  648. {
  649. if( last_width != track->m_Width ) // Find a thickness already used.
  650. {
  651. for( ii = 0; ii < trackinfo.size(); ii++ )
  652. {
  653. if( trackinfo[ii] == track->m_Width )
  654. break;
  655. }
  656. if( ii == trackinfo.size() ) // not found
  657. trackinfo.push_back( track->m_Width );
  658. last_width = track->m_Width;
  659. }
  660. }
  661. for( track = pcb->m_Zone; track != NULL; track = track->Next() )
  662. {
  663. if( last_width != track->m_Width ) // Find a thickness already used.
  664. {
  665. for( ii = 0; ii < trackinfo.size(); ii++ )
  666. {
  667. if( trackinfo[ii] == track->m_Width )
  668. break;
  669. }
  670. if( ii == trackinfo.size() ) // not found
  671. trackinfo.push_back( track->m_Width );
  672. last_width = track->m_Width;
  673. }
  674. }
  675. // Write data
  676. fputs( "$TRACKS\n", file );
  677. for( ii = 0; ii < trackinfo.size(); ii++ )
  678. {
  679. fprintf( file, "TRACK TRACK%d %d\n", trackinfo[ii], trackinfo[ii] );
  680. }
  681. fputs( "$ENDTRACKS\n\n", file );
  682. }
  683. /* Creates the shape of a footprint (section SHAPE)
  684. * The shape is always given "normal" (Orient 0, not mirrored)
  685. * Syntax:
  686. * SHAPE <shape_name>
  687. * INSERT <string> here <string> = "TH"
  688. * shape_descr (line, arc ..):
  689. * LINE startX startY endX endY
  690. * ARC startX startY endX endY centreX centreY
  691. * PAD_CIRCLE centreX scentreY radius
  692. */
  693. void FootprintWriteShape( FILE* file, MODULE* module )
  694. {
  695. EDGE_MODULE* PtEdge;
  696. EDA_BaseStruct* PtStruct;
  697. int Yaxis_sign = -1; // Control Y axis change sign (as normal
  698. // module / mirror axis and conventions)
  699. /* creates header: */
  700. fprintf( file, "SHAPE %s\n", CONV_TO_UTF8( module->m_Reference->m_Text ) );
  701. fprintf( file, "INSERT %s\n",
  702. (module->m_Attributs & MOD_CMS) ? "SMD" : "TH" );
  703. /* creates Attributes */
  704. if( module->m_Attributs != MOD_DEFAULT )
  705. {
  706. fprintf( file, "ATTRIBUTE" );
  707. if( module->m_Attributs & MOD_CMS )
  708. fprintf( file, " PAD_SMD" );
  709. if( module->m_Attributs & MOD_VIRTUAL )
  710. fprintf( file, " VIRTUAL" );
  711. fprintf( file, "\n" );
  712. }
  713. /* creates Drawing */
  714. PtStruct = module->m_Drawings;
  715. for( ; PtStruct != NULL; PtStruct = PtStruct->Next() )
  716. {
  717. switch( PtStruct->Type() )
  718. {
  719. case TYPE_TEXTE_MODULE:
  720. break;
  721. case TYPE_EDGE_MODULE:
  722. PtEdge = (EDGE_MODULE*) PtStruct;
  723. switch( PtEdge->m_Shape )
  724. {
  725. case S_SEGMENT:
  726. fprintf( file, "LINE %d %d %d %d\n",
  727. PtEdge->m_Start0.x, Yaxis_sign * PtEdge->m_Start0.y,
  728. PtEdge->m_End0.x, Yaxis_sign * PtEdge->m_End0.y );
  729. break;
  730. case S_CIRCLE:
  731. {
  732. int rayon = (int) hypot(
  733. (double) ( PtEdge->m_End0.x - PtEdge->m_Start0.x ),
  734. (double) ( PtEdge->m_End0.y - PtEdge->m_Start0.y ) );
  735. fprintf( file, "CIRCLE %d %d %d\n",
  736. PtEdge->m_Start0.x, Yaxis_sign * PtEdge->m_Start0.y,
  737. rayon );
  738. break;
  739. }
  740. case S_ARC: /* print ARC x,y start x,y end x,y center */
  741. {
  742. int arcendx, arcendy;
  743. arcendx = PtEdge->m_Start0.x;
  744. arcendy = PtEdge->m_Start0.y;
  745. RotatePoint( &arcendx, &arcendy, PtEdge->m_Angle );
  746. fprintf( file, "ARC %d %d %d %d %d %d\n",
  747. PtEdge->m_End0.x, Yaxis_sign * PtEdge->m_End0.y,
  748. arcendx, Yaxis_sign * arcendy,
  749. PtEdge->m_Start0.x, Yaxis_sign * PtEdge->m_Start0.y );
  750. break;
  751. }
  752. default:
  753. DisplayError( NULL, wxT( "Type Edge Module invalid." ) );
  754. break;
  755. } /* end switch PtEdge->m_Shape */
  756. break;
  757. default:
  758. break;
  759. } /* End switch Items type */
  760. }
  761. }