KiCad PCB EDA Suite
export_gencad.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2016 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
5  * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
7  * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
32 #include <fctsys.h>
33 #include <class_drawpanel.h>
34 #include <confirm.h>
35 #include <gestfich.h>
36 #include <pgm_base.h>
37 #include <wxPcbStruct.h>
38 #include <trigo.h>
39 #include <build_version.h>
40 #include <macros.h>
41 
42 #include <pcbnew.h>
43 
44 #include <class_board.h>
45 #include <class_module.h>
46 #include <class_track.h>
47 #include <class_edge_mod.h>
48 
49 
50 static bool CreateHeaderInfoData( FILE* aFile, PCB_EDIT_FRAME* frame );
51 static void CreateArtworksSection( FILE* aFile );
52 static void CreateTracksInfoData( FILE* aFile, BOARD* aPcb );
53 static void CreateBoardSection( FILE* aFile, BOARD* aPcb );
54 static void CreateComponentsSection( FILE* aFile, BOARD* aPcb );
55 static void CreateDevicesSection( FILE* aFile, BOARD* aPcb );
56 static void CreateRoutesSection( FILE* aFile, BOARD* aPcb );
57 static void CreateSignalsSection( FILE* aFile, BOARD* aPcb );
58 static void CreateShapesSection( FILE* aFile, BOARD* aPcb );
59 static void CreatePadsShapesSection( FILE* aFile, BOARD* aPcb );
60 static void FootprintWriteShape( FILE* File, MODULE* module );
61 
62 // layer names for Gencad export
63 
64 #if 0 // was:
65 static const wxString GenCADLayerName[] =
66 {
67  wxT( "BOTTOM" ), wxT( "INNER1" ), wxT( "INNER2" ),
68  wxT( "INNER3" ), wxT( "INNER4" ), wxT( "INNER5" ),
69  wxT( "INNER6" ), wxT( "INNER7" ), wxT( "INNER8" ),
70  wxT( "INNER9" ), wxT( "INNER10" ), wxT( "INNER11" ),
71  wxT( "INNER12" ), wxT( "INNER13" ), wxT( "INNER14" ),
72  wxT( "TOP" ), wxT( "LAYER17" ), wxT( "LAYER18" ),
73  wxT( "SOLDERPASTE_BOTTOM" ), wxT( "SOLDERPASTE_TOP" ),
74  wxT( "SILKSCREEN_BOTTOM" ), wxT( "SILKSCREEN_TOP" ),
75  wxT( "SOLDERMASK_BOTTOM" ), wxT( "SOLDERMASK_TOP" ), wxT( "LAYER25" ),
76  wxT( "LAYER26" ), wxT( "LAYER27" ), wxT( "LAYER28" ),
77  wxT( "LAYER29" ), wxT( "LAYER30" ), wxT( "LAYER31" ),
78  wxT( "LAYER32" )
79 };
80 
81 // flipped layer name for Gencad export (to make CAM350 imports correct)
82 static const wxString GenCADLayerNameFlipped[32] =
83 {
84  wxT( "TOP" ), wxT( "INNER14" ), wxT( "INNER13" ),
85  wxT( "INNER12" ), wxT( "INNER11" ), wxT( "INNER10" ),
86  wxT( "INNER9" ), wxT( "INNER8" ), wxT( "INNER7" ),
87  wxT( "INNER6" ), wxT( "INNER5" ), wxT( "INNER4" ),
88  wxT( "INNER3" ), wxT( "INNER2" ), wxT( "INNER1" ),
89  wxT( "BOTTOM" ), wxT( "LAYER17" ), wxT( "LAYER18" ),
90  wxT( "SOLDERPASTE_TOP" ), wxT( "SOLDERPASTE_BOTTOM" ),
91  wxT( "SILKSCREEN_TOP" ), wxT( "SILKSCREEN_BOTTOM" ),
92  wxT( "SOLDERMASK_TOP" ), wxT( "SOLDERMASK_BOTTOM" ), wxT( "LAYER25" ),
93  wxT( "LAYER26" ), wxT( "LAYER27" ), wxT( "LAYER28" ),
94  wxT( "LAYER29" ), wxT( "LAYER30" ), wxT( "LAYER31" ),
95  wxT( "LAYER32" )
96 };
97 
98 #else
99 
100 static std::string GenCADLayerName( int aCuCount, PCB_LAYER_ID aId )
101 {
102  if( IsCopperLayer( aId ) )
103  {
104  if( aId == F_Cu )
105  return "TOP";
106  else if( aId == B_Cu )
107  return "BOTTOM";
108 
109  else if( aId <= 14 )
110  {
111  return StrPrintf( "INNER%d", aCuCount - aId - 1 );
112  }
113  else
114  {
115  return StrPrintf( "LAYER%d", aId );
116  }
117  }
118 
119  else
120  {
121  const char* txt;
122 
123  // using a switch to clearly show mapping & catch out of bounds index.
124  switch( aId )
125  {
126  // Technicals
127  case B_Adhes: txt = "B.Adhes"; break;
128  case F_Adhes: txt = "F.Adhes"; break;
129  case B_Paste: txt = "SOLDERPASTE_BOTTOM"; break;
130  case F_Paste: txt = "SOLDERPASTE_TOP"; break;
131  case B_SilkS: txt = "SILKSCREEN_BOTTOM"; break;
132  case F_SilkS: txt = "SILKSCREEN_TOP"; break;
133  case B_Mask: txt = "SOLDERMASK_BOTTOM"; break;
134  case F_Mask: txt = "SOLDERMASK_TOP"; break;
135 
136  // Users
137  case Dwgs_User: txt = "Dwgs.User"; break;
138  case Cmts_User: txt = "Cmts.User"; break;
139  case Eco1_User: txt = "Eco1.User"; break;
140  case Eco2_User: txt = "Eco2.User"; break;
141  case Edge_Cuts: txt = "Edge.Cuts"; break;
142  case Margin: txt = "Margin"; break;
143 
144  // Footprint
145  case F_CrtYd: txt = "F_CrtYd"; break;
146  case B_CrtYd: txt = "B_CrtYd"; break;
147  case F_Fab: txt = "F_Fab"; break;
148  case B_Fab: txt = "B_Fab"; break;
149 
150  default:
151  wxASSERT_MSG( 0, wxT( "aId UNEXPECTED" ) );
152  txt = "BAD-INDEX!"; break;
153  }
154 
155  return txt;
156  }
157 };
158 
159 
160 static const PCB_LAYER_ID gc_seq[] = {
161  B_Cu,
162  In30_Cu,
163  In29_Cu,
164  In28_Cu,
165  In27_Cu,
166  In26_Cu,
167  In25_Cu,
168  In24_Cu,
169  In23_Cu,
170  In22_Cu,
171  In21_Cu,
172  In20_Cu,
173  In19_Cu,
174  In18_Cu,
175  In17_Cu,
176  In16_Cu,
177  In15_Cu,
178  In14_Cu,
179  In13_Cu,
180  In12_Cu,
181  In11_Cu,
182  In10_Cu,
183  In9_Cu,
184  In8_Cu,
185  In7_Cu,
186  In6_Cu,
187  In5_Cu,
188  In4_Cu,
189  In3_Cu,
190  In2_Cu,
191  In1_Cu,
192  F_Cu,
193 };
194 
195 
196 // flipped layer name for Gencad export (to make CAM350 imports correct)
197 static std::string GenCADLayerNameFlipped( int aCuCount, PCB_LAYER_ID aId )
198 {
199  if( 1<= aId && aId <= 14 )
200  {
201  return StrPrintf( "INNER%d", 14 - aId );
202  }
203 
204  return GenCADLayerName( aCuCount, aId );
205 };
206 
207 
208 #endif
209 
210 static std::string fmt_mask( LSET aSet )
211 {
212 #if 0
213  return aSet.FmtHex();
214 #else
215  return StrPrintf( "%08x", (unsigned) ( aSet & LSET::AllCuMask() ).to_ulong() );
216 #endif
217 }
218 
219 
220 // These are the export origin (the auxiliary axis)
222 
223 // GerbTool chokes on units different than INCH so this is the conversion factor
224 const static double SCALE_FACTOR = 1000.0 * IU_PER_MILS;
225 
226 
227 /* Two helper functions to calculate coordinates of modules in gencad values
228  * (GenCAD Y axis from bottom to top)
229  */
230 static double MapXTo( int aX )
231 {
232  return (aX - GencadOffsetX) / SCALE_FACTOR;
233 }
234 
235 
236 static double MapYTo( int aY )
237 {
238  return (GencadOffsetY - aY) / SCALE_FACTOR;
239 }
240 
241 
242 /* Driver function: processing starts here */
243 void PCB_EDIT_FRAME::ExportToGenCAD( wxCommandEvent& aEvent )
244 {
245  wxFileName fn = GetBoard()->GetFileName();
246  FILE* file;
247 
248  wxString ext = wxT( "cad" );
249  wxString wildcard = _( "GenCAD 1.4 board files (.cad)|*.cad" );
250 
251  fn.SetExt( ext );
252 
253  wxString pro_dir = wxPathOnly( Prj().GetProjectFullName() );
254 
255  wxFileDialog dlg( this, _( "Save GenCAD Board File" ), pro_dir,
256  fn.GetFullName(), wildcard,
257  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
258 
259  if( dlg.ShowModal() == wxID_CANCEL )
260  return;
261 
262  if( ( file = wxFopen( dlg.GetPath(), wxT( "wt" ) ) ) == NULL )
263  {
264  wxString msg;
265 
266  msg.Printf( _( "Unable to create <%s>" ), GetChars( dlg.GetPath() ) );
267  DisplayError( this, msg ); return;
268  }
269 
270  // Switch the locale to standard C (needed to print floating point numbers)
271  LOCALE_IO toggle;
272 
273  // Update some board data, to ensure a reliable gencad export
275 
276  // Save the auxiliary origin for the rest of the module
279 
280  // No idea on *why* this should be needed... maybe to fix net names?
281  Compile_Ratsnest( NULL, true );
282 
283  /* Temporary modification of footprints that are flipped (i.e. on bottom
284  * layer) to convert them to non flipped footprints.
285  * This is necessary to easily export shapes to GenCAD,
286  * that are given as normal orientation (non flipped, rotation = 0))
287  * these changes will be undone later
288  */
289  BOARD* pcb = GetBoard();
290  MODULE* module;
291 
292  for( module = pcb->m_Modules; module; module = module->Next() )
293  {
294  module->SetFlag( 0 );
295 
296  if( module->GetLayer() == B_Cu )
297  {
298  module->Flip( module->GetPosition() );
299  module->SetFlag( 1 );
300  }
301  }
302 
303  /* Gencad has some mandatory and some optional sections: some importer
304  * need the padstack section (which is optional) anyway. Also the
305  * order of the section *is* important */
306 
307  CreateHeaderInfoData( file, this ); // Gencad header
308  CreateBoardSection( file, pcb ); // Board perimeter
309 
310  CreatePadsShapesSection( file, pcb ); // Pads and padstacks
311  CreateArtworksSection( file ); // Empty but mandatory
312 
313  /* Gencad splits a component info in shape, component and device.
314  * We don't do any sharing (it would be difficult since each module is
315  * customizable after placement) */
316  CreateShapesSection( file, pcb );
317  CreateComponentsSection( file, pcb );
318  CreateDevicesSection( file, pcb );
319 
320  // In a similar way the netlist is split in net, track and route
321  CreateSignalsSection( file, pcb );
322  CreateTracksInfoData( file, pcb );
323  CreateRoutesSection( file, pcb );
324 
325  fclose( file );
326 
327  // Undo the footprints modifications (flipped footprints)
328  for( module = pcb->m_Modules; module; module = module->Next() )
329  {
330  if( module->GetFlag() )
331  {
332  module->Flip( module->GetPosition() );
333  module->SetFlag( 0 );
334  }
335  }
336 }
337 
338 
339 // Comparator for sorting pads with qsort
340 static int PadListSortByShape( const void* aRefptr, const void* aObjptr )
341 {
342  const D_PAD* padref = *(D_PAD**) aRefptr;
343  const D_PAD* padcmp = *(D_PAD**) aObjptr;
344 
345  return D_PAD::Compare( padref, padcmp );
346 }
347 
348 
349 // Sort vias for uniqueness
350 static int ViaSort( const void* aRefptr, const void* aObjptr )
351 {
352  VIA* padref = *(VIA**) aRefptr;
353  VIA* padcmp = *(VIA**) aObjptr;
354 
355  if( padref->GetWidth() != padcmp->GetWidth() )
356  return padref->GetWidth() - padcmp->GetWidth();
357 
358  if( padref->GetDrillValue() != padcmp->GetDrillValue() )
359  return padref->GetDrillValue() - padcmp->GetDrillValue();
360 
361  if( padref->GetLayerSet() != padcmp->GetLayerSet() )
362  return padref->GetLayerSet().FmtBin().compare( padcmp->GetLayerSet().FmtBin() );
363 
364  return 0;
365 }
366 
367 
368 // The ARTWORKS section is empty but (officially) mandatory
369 static void CreateArtworksSection( FILE* aFile )
370 {
371  /* The artworks section is empty */
372  fputs( "$ARTWORKS\n", aFile );
373  fputs( "$ENDARTWORKS\n\n", aFile );
374 }
375 
376 
377 // Emit PADS and PADSTACKS. They are sorted and emitted uniquely.
378 // Via name is synthesized from their attributes, pads are numbered
379 static void CreatePadsShapesSection( FILE* aFile, BOARD* aPcb )
380 {
381  std::vector<D_PAD*> pads;
382  std::vector<D_PAD*> padstacks;
383  std::vector<VIA*> vias;
384  std::vector<VIA*> viastacks;
385 
386  padstacks.resize( 1 ); // We count pads from 1
387 
388  // The master layermask (i.e. the enabled layers) for padstack generation
389  LSET master_layermask = aPcb->GetDesignSettings().GetEnabledLayers();
390  int cu_count = aPcb->GetCopperLayerCount();
391 
392  fputs( "$PADS\n", aFile );
393 
394  // Enumerate and sort the pads
395  if( aPcb->GetPadCount() > 0 )
396  {
397  pads = aPcb->GetPads();
398  qsort( &pads[0], aPcb->GetPadCount(), sizeof( D_PAD* ),
400  }
401 
402  // The same for vias
403  for( VIA* via = GetFirstVia( aPcb->m_Track ); via;
404  via = GetFirstVia( via->Next() ) )
405  {
406  vias.push_back( via );
407  }
408 
409  qsort( &vias[0], vias.size(), sizeof(VIA*), ViaSort );
410 
411  // Emit vias pads
412  TRACK* old_via = 0;
413 
414  for( unsigned i = 0; i < vias.size(); i++ )
415  {
416  VIA* via = vias[i];
417 
418  if( old_via && 0 == ViaSort( &old_via, &via ) )
419  continue;
420 
421  old_via = via;
422  viastacks.push_back( via );
423  fprintf( aFile, "PAD V%d.%d.%s ROUND %g\nCIRCLE 0 0 %g\n",
424  via->GetWidth(), via->GetDrillValue(),
425  fmt_mask( via->GetLayerSet() ).c_str(),
426  via->GetDrillValue() / SCALE_FACTOR,
427  via->GetWidth() / (SCALE_FACTOR * 2) );
428  }
429 
430  // Emit component pads
431  D_PAD* old_pad = 0;
432  int pad_name_number = 0;
433 
434  for( unsigned i = 0; i<pads.size(); ++i )
435  {
436  D_PAD* pad = pads[i];
437 
438  pad->SetSubRatsnest( pad_name_number );
439 
440  if( old_pad && 0==D_PAD::Compare( old_pad, pad ) )
441  continue; // already created
442 
443  old_pad = pad;
444 
445  pad_name_number++;
446  pad->SetSubRatsnest( pad_name_number );
447 
448  fprintf( aFile, "PAD P%d", pad->GetSubRatsnest() );
449 
450  padstacks.push_back( pad ); // Will have its own padstack later
451  int dx = pad->GetSize().x / 2;
452  int dy = pad->GetSize().y / 2;
453 
454  switch( pad->GetShape() )
455  {
456  default:
457  case PAD_SHAPE_CIRCLE:
458  fprintf( aFile, " ROUND %g\n",
459  pad->GetDrillSize().x / SCALE_FACTOR );
460  /* Circle is center, radius */
461  fprintf( aFile, "CIRCLE %g %g %g\n",
462  pad->GetOffset().x / SCALE_FACTOR,
463  -pad->GetOffset().y / SCALE_FACTOR,
464  pad->GetSize().x / (SCALE_FACTOR * 2) );
465  break;
466 
467  case PAD_SHAPE_RECT:
468  fprintf( aFile, " RECTANGULAR %g\n",
469  pad->GetDrillSize().x / SCALE_FACTOR );
470 
471  // Rectangle is begin, size *not* begin, end!
472  fprintf( aFile, "RECTANGLE %g %g %g %g\n",
473  (-dx + pad->GetOffset().x ) / SCALE_FACTOR,
474  (-dy - pad->GetOffset().y ) / SCALE_FACTOR,
475  dx / (SCALE_FACTOR / 2), dy / (SCALE_FACTOR / 2) );
476  break;
477 
478  case PAD_SHAPE_OVAL: // Create outline by 2 lines and 2 arcs
479  {
480  // OrCAD Layout call them OVAL or OBLONG - GenCAD call them FINGERs
481  fprintf( aFile, " FINGER %g\n",
482  pad->GetDrillSize().x / SCALE_FACTOR );
483  int dr = dx - dy;
484 
485  if( dr >= 0 ) // Horizontal oval
486  {
487  int radius = dy;
488  fprintf( aFile, "LINE %g %g %g %g\n",
489  (-dr + pad->GetOffset().x) / SCALE_FACTOR,
490  (-pad->GetOffset().y - radius) / SCALE_FACTOR,
491  (dr + pad->GetOffset().x ) / SCALE_FACTOR,
492  (-pad->GetOffset().y - radius) / SCALE_FACTOR );
493 
494  // GenCAD arcs are (start, end, center)
495  fprintf( aFile, "ARC %g %g %g %g %g %g\n",
496  (dr + pad->GetOffset().x) / SCALE_FACTOR,
497  (-pad->GetOffset().y - radius) / SCALE_FACTOR,
498  (dr + pad->GetOffset().x) / SCALE_FACTOR,
499  (-pad->GetOffset().y + radius) / SCALE_FACTOR,
500  (dr + pad->GetOffset().x) / SCALE_FACTOR,
501  -pad->GetOffset().y / SCALE_FACTOR );
502 
503  fprintf( aFile, "LINE %g %g %g %g\n",
504  (dr + pad->GetOffset().x) / SCALE_FACTOR,
505  (-pad->GetOffset().y + radius) / SCALE_FACTOR,
506  (-dr + pad->GetOffset().x) / SCALE_FACTOR,
507  (-pad->GetOffset().y + radius) / SCALE_FACTOR );
508  fprintf( aFile, "ARC %g %g %g %g %g %g\n",
509  (-dr + pad->GetOffset().x) / SCALE_FACTOR,
510  (-pad->GetOffset().y + radius) / SCALE_FACTOR,
511  (-dr + pad->GetOffset().x) / SCALE_FACTOR,
512  (-pad->GetOffset().y - radius) / SCALE_FACTOR,
513  (-dr + pad->GetOffset().x) / SCALE_FACTOR,
514  -pad->GetOffset().y / SCALE_FACTOR );
515  }
516  else // Vertical oval
517  {
518  dr = -dr;
519  int radius = dx;
520  fprintf( aFile, "LINE %g %g %g %g\n",
521  (-radius + pad->GetOffset().x) / SCALE_FACTOR,
522  (-pad->GetOffset().y - dr) / SCALE_FACTOR,
523  (-radius + pad->GetOffset().x ) / SCALE_FACTOR,
524  (-pad->GetOffset().y + dr) / SCALE_FACTOR );
525  fprintf( aFile, "ARC %g %g %g %g %g %g\n",
526  (-radius + pad->GetOffset().x ) / SCALE_FACTOR,
527  (-pad->GetOffset().y + dr) / SCALE_FACTOR,
528  (radius + pad->GetOffset().x ) / SCALE_FACTOR,
529  (-pad->GetOffset().y + dr) / SCALE_FACTOR,
530  pad->GetOffset().x / SCALE_FACTOR,
531  (-pad->GetOffset().y + dr) / SCALE_FACTOR );
532 
533  fprintf( aFile, "LINE %g %g %g %g\n",
534  (radius + pad->GetOffset().x) / SCALE_FACTOR,
535  (-pad->GetOffset().y + dr) / SCALE_FACTOR,
536  (radius + pad->GetOffset().x) / SCALE_FACTOR,
537  (-pad->GetOffset().y - dr) / SCALE_FACTOR );
538  fprintf( aFile, "ARC %g %g %g %g %g %g\n",
539  (radius + pad->GetOffset().x) / SCALE_FACTOR,
540  (-pad->GetOffset().y - dr) / SCALE_FACTOR,
541  (-radius + pad->GetOffset().x) / SCALE_FACTOR,
542  (-pad->GetOffset().y - dr) / SCALE_FACTOR,
543  pad->GetOffset().x / SCALE_FACTOR,
544  (-pad->GetOffset().y - dr) / SCALE_FACTOR );
545  }
546  }
547  break;
548 
549  case PAD_SHAPE_TRAPEZOID:
550  fprintf( aFile, " POLYGON %g\n",
551  pad->GetDrillSize().x / SCALE_FACTOR );
552 
553  // XXX TO BE IMPLEMENTED! and I don't know if it could be actually imported by something
554  break;
555  }
556  }
557 
558  fputs( "\n$ENDPADS\n\n", aFile );
559 
560  // Now emit the padstacks definitions, using the combined layer masks
561  fputs( "$PADSTACKS\n", aFile );
562 
563  // Via padstacks
564  for( unsigned i = 0; i < viastacks.size(); i++ )
565  {
566  VIA* via = viastacks[i];
567 
568  LSET mask = via->GetLayerSet() & master_layermask;
569 
570  fprintf( aFile, "PADSTACK VIA%d.%d.%s %g\n",
571  via->GetWidth(), via->GetDrillValue(),
572  fmt_mask( mask ).c_str(),
573  via->GetDrillValue() / SCALE_FACTOR );
574 
575  for( LSEQ seq = mask.Seq( gc_seq, DIM( gc_seq ) ); seq; ++seq )
576  {
577  PCB_LAYER_ID layer = *seq;
578 
579  fprintf( aFile, "PAD V%d.%d.%s %s 0 0\n",
580  via->GetWidth(), via->GetDrillValue(),
581  fmt_mask( mask ).c_str(),
582  GenCADLayerName( cu_count, layer ).c_str()
583  );
584  }
585  }
586 
587  /* Component padstacks
588  * CAM350 don't apply correctly the FLIP semantics for padstacks, i.e. doesn't
589  * swap the top and bottom layers... so I need to define the shape as MIRRORX
590  * and define a separate 'flipped' padstack... until it appears yet another
591  * noncompliant importer */
592  for( unsigned i = 1; i < padstacks.size(); i++ )
593  {
594  D_PAD* pad = padstacks[i];
595 
596  // Straight padstack
597  fprintf( aFile, "PADSTACK PAD%u %g\n", i, pad->GetDrillSize().x / SCALE_FACTOR );
598 
599  LSET pad_set = pad->GetLayerSet() & master_layermask;
600 
601  // the special gc_seq
602  for( LSEQ seq = pad_set.Seq( gc_seq, DIM( gc_seq ) ); seq; ++seq )
603  {
604  PCB_LAYER_ID layer = *seq;
605 
606  fprintf( aFile, "PAD P%u %s 0 0\n", i, GenCADLayerName( cu_count, layer ).c_str() );
607  }
608 
609  // Flipped padstack
610  fprintf( aFile, "PADSTACK PAD%uF %g\n", i, pad->GetDrillSize().x / SCALE_FACTOR );
611 
612  // the normal PCB_LAYER_ID sequence is inverted from gc_seq[]
613  for( LSEQ seq = pad_set.Seq(); seq; ++seq )
614  {
615  PCB_LAYER_ID layer = *seq;
616 
617  fprintf( aFile, "PAD P%u %s 0 0\n", i, GenCADLayerNameFlipped( cu_count, layer ).c_str() );
618  }
619  }
620 
621  fputs( "$ENDPADSTACKS\n\n", aFile );
622 }
623 
624 
625 /* Creates the footprint shape list.
626  * Since module shape is customizable after the placement we cannot share them;
627  * instead we opt for the one-module-one-shape-one-component-one-device approach
628  */
629 static void CreateShapesSection( FILE* aFile, BOARD* aPcb )
630 {
631  MODULE* module;
632  D_PAD* pad;
633  const char* layer;
634  wxString pinname;
635  const char* mirror = "0";
636 
637  fputs( "$SHAPES\n", aFile );
638 
639  const LSET all_cu = LSET::AllCuMask();
640 
641  for( module = aPcb->m_Modules; module; module = module->Next() )
642  {
643  FootprintWriteShape( aFile, module );
644 
645  for( pad = module->PadsList(); pad; pad = pad->Next() )
646  {
647  /* Funny thing: GenCAD requires the pad side even if you use
648  * padstacks (which are theorically optional but gerbtools
649  *requires* them). Now the trouble thing is that 'BOTTOM'
650  * is interpreted by someone as a padstack flip even
651  * if the spec explicitly says it's not... */
652  layer = "ALL";
653 
654  if( ( pad->GetLayerSet() & all_cu ) == LSET( B_Cu ) )
655  {
656  layer = module->GetFlag() ? "TOP" : "BOTTOM";
657  }
658  else if( ( pad->GetLayerSet() & all_cu ) == LSET( F_Cu ) )
659  {
660  layer = module->GetFlag() ? "BOTTOM" : "TOP";
661  }
662 
663  pad->StringPadName( pinname );
664 
665  if( pinname.IsEmpty() )
666  pinname = wxT( "none" );
667 
668  double orient = pad->GetOrientation() - module->GetOrientation();
669  NORMALIZE_ANGLE_POS( orient );
670 
671  // Bottom side modules use the flipped padstack
672  fprintf( aFile, (module->GetFlag()) ?
673  "PIN %s PAD%dF %g %g %s %g %s\n" :
674  "PIN %s PAD%d %g %g %s %g %s\n",
675  TO_UTF8( pinname ), pad->GetSubRatsnest(),
676  pad->GetPos0().x / SCALE_FACTOR,
677  -pad->GetPos0().y / SCALE_FACTOR,
678  layer, orient / 10.0, mirror );
679  }
680  }
681 
682  fputs( "$ENDSHAPES\n\n", aFile );
683 }
684 
685 
686 /* Creates the section $COMPONENTS (Footprints placement)
687  * Bottom side components are difficult to handle: shapes must be mirrored or
688  * flipped, silk layers need to be handled correctly and so on. Also it seems
689  * that *noone* follows the specs...
690  */
691 static void CreateComponentsSection( FILE* aFile, BOARD* aPcb )
692 {
693  fputs( "$COMPONENTS\n", aFile );
694 
695  int cu_count = aPcb->GetCopperLayerCount();
696 
697  for( MODULE* module = aPcb->m_Modules; module; module = module->Next() )
698  {
699  const char* mirror;
700  const char* flip;
701  double fp_orient = module->GetOrientation();
702 
703  if( module->GetFlag() )
704  {
705  mirror = "0";
706  flip = "FLIP";
707  NEGATE_AND_NORMALIZE_ANGLE_POS( fp_orient );
708  }
709  else
710  {
711  mirror = "0";
712  flip = "0";
713  }
714 
715  fprintf( aFile, "\nCOMPONENT %s\n",
716  TO_UTF8( module->GetReference() ) );
717  fprintf( aFile, "DEVICE %s_%s\n",
718  TO_UTF8( module->GetReference() ),
719  TO_UTF8( module->GetValue() ) );
720  fprintf( aFile, "PLACE %g %g\n",
721  MapXTo( module->GetPosition().x ),
722  MapYTo( module->GetPosition().y ) );
723  fprintf( aFile, "LAYER %s\n",
724  (module->GetFlag()) ? "BOTTOM" : "TOP" );
725  fprintf( aFile, "ROTATION %g\n",
726  fp_orient / 10.0 );
727  fprintf( aFile, "SHAPE %s %s %s\n",
728  TO_UTF8( module->GetReference() ),
729  mirror, flip );
730 
731  // Text on silk layer: RefDes and value (are they actually useful?)
732  TEXTE_MODULE *textmod = &module->Reference();
733 
734  for( int ii = 0; ii < 2; ii++ )
735  {
736  double txt_orient = textmod->GetTextAngle();
737  std::string layer = GenCADLayerName( cu_count, module->GetFlag() ? B_SilkS : F_SilkS );
738 
739  fprintf( aFile, "TEXT %g %g %g %g %s %s \"%s\"",
740  textmod->GetPos0().x / SCALE_FACTOR,
741  -textmod->GetPos0().y / SCALE_FACTOR,
742  textmod->GetTextWidth() / SCALE_FACTOR,
743  txt_orient / 10.0,
744  mirror,
745  layer.c_str(),
746  TO_UTF8( textmod->GetText() ) );
747 
748  // Please note, the width is approx
749  fprintf( aFile, " 0 0 %g %g\n",
750  ( textmod->GetTextWidth() * textmod->GetLength() ) / SCALE_FACTOR,
751  textmod->GetTextHeight() / SCALE_FACTOR );
752 
753  textmod = &module->Value(); // Dirty trick for the second iteration
754  }
755 
756  // The SHEET is a 'generic description' for referencing the component
757  fprintf( aFile, "SHEET \"RefDes: %s, Value: %s\"\n",
758  TO_UTF8( module->GetReference() ),
759  TO_UTF8( module->GetValue() ) );
760  }
761 
762  fputs( "$ENDCOMPONENTS\n\n", aFile );
763 }
764 
765 
766 /* Emit the netlist (which is actually the thing for which GenCAD is used these
767  * days!); tracks are handled later */
768 static void CreateSignalsSection( FILE* aFile, BOARD* aPcb )
769 {
770  wxString msg;
771  NETINFO_ITEM* net;
772  D_PAD* pad;
773  MODULE* module;
774  int NbNoConn = 1;
775 
776  fputs( "$SIGNALS\n", aFile );
777 
778  for( unsigned ii = 0; ii < aPcb->GetNetCount(); ii++ )
779  {
780  net = aPcb->FindNet( ii );
781 
782  if( net->GetNetname() == wxEmptyString ) // dummy netlist (no connection)
783  {
784  msg.Printf( "NoConnection%d", NbNoConn++ );
785  }
786 
787  if( net->GetNet() <= 0 ) // dummy netlist (no connection)
788  continue;
789 
790  msg = wxT( "SIGNAL " ) + net->GetNetname();
791 
792  fputs( TO_UTF8( msg ), aFile );
793  fputs( "\n", aFile );
794 
795  for( module = aPcb->m_Modules; module; module = module->Next() )
796  {
797  for( pad = module->PadsList(); pad; pad = pad->Next() )
798  {
799  wxString padname;
800 
801  if( pad->GetNetCode() != net->GetNet() )
802  continue;
803 
804  pad->StringPadName( padname );
805  msg.Printf( wxT( "NODE %s %s" ),
806  GetChars( module->GetReference() ),
807  GetChars( padname ) );
808 
809  fputs( TO_UTF8( msg ), aFile );
810  fputs( "\n", aFile );
811  }
812  }
813  }
814 
815  fputs( "$ENDSIGNALS\n\n", aFile );
816 }
817 
818 
819 // Creates the header section
820 static bool CreateHeaderInfoData( FILE* aFile, PCB_EDIT_FRAME* aFrame )
821 {
822  wxString msg;
823  BOARD *board = aFrame->GetBoard();
824 
825  fputs( "$HEADER\n", aFile );
826  fputs( "GENCAD 1.4\n", aFile );
827 
828  // Please note: GenCAD syntax requires quoted strings if they can contain spaces
829  msg.Printf( wxT( "USER \"%s %s\"\n" ),
830  GetChars( Pgm().App().GetAppName() ),
831  GetChars( GetBuildVersion() ) );
832  fputs( TO_UTF8( msg ), aFile );
833 
834  msg = wxT( "DRAWING \"" ) + board->GetFileName() + wxT( "\"\n" );
835  fputs( TO_UTF8( msg ), aFile );
836 
837  const TITLE_BLOCK& tb = aFrame->GetTitleBlock();
838 
839  msg = wxT( "REVISION \"" ) + tb.GetRevision() + wxT( " " ) + tb.GetDate() + wxT( "\"\n" );
840 
841  fputs( TO_UTF8( msg ), aFile );
842  fputs( "UNITS INCH\n", aFile );
843 
844  msg.Printf( wxT( "ORIGIN %g %g\n" ),
845  MapXTo( aFrame->GetAuxOrigin().x ),
846  MapYTo( aFrame->GetAuxOrigin().y ) );
847  fputs( TO_UTF8( msg ), aFile );
848 
849  fputs( "INTERTRACK 0\n", aFile );
850  fputs( "$ENDHEADER\n\n", aFile );
851 
852  return true;
853 }
854 
855 
856 /*
857  * Sort function used to sort tracks segments:
858  * items are sorted by netcode, then by width then by layer
859  */
860 static int TrackListSortByNetcode( const void* refptr, const void* objptr )
861 {
862  const TRACK* ref, * cmp;
863  int diff;
864 
865  ref = *( (TRACK**) refptr );
866  cmp = *( (TRACK**) objptr );
867 
868  if( ( diff = ref->GetNetCode() - cmp->GetNetCode() ) )
869  return diff;
870 
871  if( ( diff = ref->GetWidth() - cmp->GetWidth() ) )
872  return diff;
873 
874  if( ( diff = ref->GetLayer() - cmp->GetLayer() ) )
875  return diff;
876 
877  return 0;
878 }
879 
880 
881 /* Creates the section ROUTES
882  * that handles tracks, vias
883  * TODO: add zones
884  * section:
885  * $ROUTE
886  * ...
887  * $ENROUTE
888  * Track segments must be sorted by nets
889  */
890 static void CreateRoutesSection( FILE* aFile, BOARD* aPcb )
891 {
892  TRACK* track, ** tracklist;
893  int vianum = 1;
894  int old_netcode, old_width, old_layer;
895  int nbitems, ii;
896  LSET master_layermask = aPcb->GetDesignSettings().GetEnabledLayers();
897 
898  int cu_count = aPcb->GetCopperLayerCount();
899 
900  // Count items
901  nbitems = 0;
902 
903  for( track = aPcb->m_Track; track; track = track->Next() )
904  nbitems++;
905 
906  for( track = aPcb->m_Zone; track; track = track->Next() )
907  {
908  if( track->Type() == PCB_ZONE_T )
909  nbitems++;
910  }
911 
912  tracklist = (TRACK**) operator new( (nbitems + 1)* sizeof( TRACK* ) );
913 
914  nbitems = 0;
915 
916  for( track = aPcb->m_Track; track; track = track->Next() )
917  tracklist[nbitems++] = track;
918 
919  for( track = aPcb->m_Zone; track; track = track->Next() )
920  {
921  if( track->Type() == PCB_ZONE_T )
922  tracklist[nbitems++] = track;
923  }
924 
925  tracklist[nbitems] = NULL;
926 
927  qsort( tracklist, nbitems, sizeof(TRACK*), TrackListSortByNetcode );
928 
929  fputs( "$ROUTES\n", aFile );
930 
931  old_netcode = -1; old_width = -1; old_layer = -1;
932 
933  for( ii = 0; ii < nbitems; ii++ )
934  {
935  track = tracklist[ii];
936 
937  if( old_netcode != track->GetNetCode() )
938  {
939  old_netcode = track->GetNetCode();
940  NETINFO_ITEM* net = track->GetNet();
941  wxString netname;
942 
943  if( net && (net->GetNetname() != wxEmptyString) )
944  netname = net->GetNetname();
945  else
946  netname = wxT( "_noname_" );
947 
948  fprintf( aFile, "ROUTE %s\n", TO_UTF8( netname ) );
949  }
950 
951  if( old_width != track->GetWidth() )
952  {
953  old_width = track->GetWidth();
954  fprintf( aFile, "TRACK TRACK%d\n", track->GetWidth() );
955  }
956 
957  if( (track->Type() == PCB_TRACE_T) || (track->Type() == PCB_ZONE_T) )
958  {
959  if( old_layer != track->GetLayer() )
960  {
961  old_layer = track->GetLayer();
962  fprintf( aFile, "LAYER %s\n",
963  GenCADLayerName( cu_count, track->GetLayer() ).c_str()
964  );
965  }
966 
967  fprintf( aFile, "LINE %g %g %g %g\n",
968  MapXTo( track->GetStart().x ), MapYTo( track->GetStart().y ),
969  MapXTo( track->GetEnd().x ), MapYTo( track->GetEnd().y ) );
970  }
971 
972  if( track->Type() == PCB_VIA_T )
973  {
974  const VIA* via = static_cast<const VIA*>(track);
975 
976  LSET vset = via->GetLayerSet() & master_layermask;
977 
978  fprintf( aFile, "VIA VIA%d.%d.%s %g %g ALL %g via%d\n",
979  via->GetWidth(), via->GetDrillValue(),
980  fmt_mask( vset ).c_str(),
981  MapXTo( via->GetStart().x ), MapYTo( via->GetStart().y ),
982  via->GetDrillValue() / SCALE_FACTOR, vianum++ );
983  }
984  }
985 
986  fputs( "$ENDROUTES\n\n", aFile );
987 
988  delete tracklist;
989 }
990 
991 
992 /* Creates the section $DEVICES
993  * This is a list of footprints properties
994  * ( Shapes are in section $SHAPE )
995  */
996 static void CreateDevicesSection( FILE* aFile, BOARD* aPcb )
997 {
998  MODULE* module;
999 
1000  fputs( "$DEVICES\n", aFile );
1001 
1002  for( module = aPcb->m_Modules; module; module = module->Next() )
1003  {
1004  fprintf( aFile, "DEVICE \"%s\"\n", TO_UTF8( module->GetReference() ) );
1005  fprintf( aFile, "PART \"%s\"\n", TO_UTF8( module->GetValue() ) );
1006  fprintf( aFile, "PACKAGE \"%s\"\n", module->GetFPID().Format().c_str() );
1007 
1008  // The TYPE attribute is almost freeform
1009  const char* ty = "TH";
1010 
1011  if( module->GetAttributes() & MOD_CMS )
1012  ty = "SMD";
1013 
1014  if( module->GetAttributes() & MOD_VIRTUAL )
1015  ty = "VIRTUAL";
1016 
1017  fprintf( aFile, "TYPE %s\n", ty );
1018  }
1019 
1020  fputs( "$ENDDEVICES\n\n", aFile );
1021 }
1022 
1023 
1024 /* Creates the section $BOARD.
1025  * We output here only the board perimeter
1026  */
1027 static void CreateBoardSection( FILE* aFile, BOARD* aPcb )
1028 {
1029  fputs( "$BOARD\n", aFile );
1030 
1031  // Extract the board edges
1032  for( auto drawing : aPcb->Drawings() )
1033  {
1034  if( drawing->Type() == PCB_LINE_T )
1035  {
1036  DRAWSEGMENT* drawseg = static_cast<DRAWSEGMENT*>( drawing );
1037  if( drawseg->GetLayer() == Edge_Cuts )
1038  {
1039  // XXX GenCAD supports arc boundaries but I've seen nothing that reads them
1040  fprintf( aFile, "LINE %g %g %g %g\n",
1041  MapXTo( drawseg->GetStart().x ), MapYTo( drawseg->GetStart().y ),
1042  MapXTo( drawseg->GetEnd().x ), MapYTo( drawseg->GetEnd().y ) );
1043  }
1044  }
1045  }
1046 
1047  fputs( "$ENDBOARD\n\n", aFile );
1048 }
1049 
1050 
1051 /* Creates the section "$TRACKS"
1052  * This sections give the list of widths (tools) used in tracks and vias
1053  * format:
1054  * $TRACK
1055  * TRACK <name> <width>
1056  * $ENDTRACK
1057  *
1058  * Each tool name is build like this: "TRACK" + track width.
1059  * For instance for a width = 120 : name = "TRACK120".
1060  */
1061 static void CreateTracksInfoData( FILE* aFile, BOARD* aPcb )
1062 {
1063  TRACK* track;
1064  int last_width = -1;
1065 
1066  // Find thickness used for traces
1067  // XXX could use the same sorting approach used for pads
1068 
1069  std::vector <int> trackinfo;
1070 
1071  unsigned ii;
1072 
1073  for( track = aPcb->m_Track; track; track = track->Next() )
1074  {
1075  if( last_width != track->GetWidth() ) // Find a thickness already used.
1076  {
1077  for( ii = 0; ii < trackinfo.size(); ii++ )
1078  {
1079  if( trackinfo[ii] == track->GetWidth() )
1080  break;
1081  }
1082 
1083  if( ii == trackinfo.size() ) // not found
1084  trackinfo.push_back( track->GetWidth() );
1085 
1086  last_width = track->GetWidth();
1087  }
1088  }
1089 
1090  for( track = aPcb->m_Zone; track; track = track->Next() )
1091  {
1092  if( last_width != track->GetWidth() ) // Find a thickness already used.
1093  {
1094  for( ii = 0; ii < trackinfo.size(); ii++ )
1095  {
1096  if( trackinfo[ii] == track->GetWidth() )
1097  break;
1098  }
1099 
1100  if( ii == trackinfo.size() ) // not found
1101  trackinfo.push_back( track->GetWidth() );
1102 
1103  last_width = track->GetWidth();
1104  }
1105  }
1106 
1107  // Write data
1108  fputs( "$TRACKS\n", aFile );
1109 
1110  for( ii = 0; ii < trackinfo.size(); ii++ )
1111  {
1112  fprintf( aFile, "TRACK TRACK%d %g\n", trackinfo[ii],
1113  trackinfo[ii] / SCALE_FACTOR );
1114  }
1115 
1116  fputs( "$ENDTRACKS\n\n", aFile );
1117 }
1118 
1119 
1120 /* Creates the shape of a footprint (section SHAPE)
1121  * The shape is always given "normal" (Orient 0, not mirrored)
1122  * It's almost guaranteed that the silk layer will be imported wrong but
1123  * the shape also contains the pads!
1124  */
1125 static void FootprintWriteShape( FILE* aFile, MODULE* module )
1126 {
1127  EDGE_MODULE* PtEdge;
1128  EDA_ITEM* PtStruct;
1129 
1130  // Control Y axis change sign for flipped modules
1131  int Yaxis_sign = -1;
1132 
1133  // Flip for bottom side components
1134  if( module->GetFlag() )
1135  Yaxis_sign = 1;
1136 
1137  /* creates header: */
1138  fprintf( aFile, "\nSHAPE %s\n", TO_UTF8( module->GetReference() ) );
1139 
1140  if( module->GetAttributes() & MOD_VIRTUAL )
1141  {
1142  fprintf( aFile, "INSERT SMD\n" );
1143  }
1144  else
1145  {
1146  if( module->GetAttributes() & MOD_CMS )
1147  {
1148  fprintf( aFile, "INSERT SMD\n" );
1149  }
1150  else
1151  {
1152  fprintf( aFile, "INSERT TH\n" );
1153  }
1154  }
1155 
1156 #if 0 /* ATTRIBUTE name and value is unspecified and the original exporter
1157  * got the syntax wrong, so CAM350 rejected the whole shape! */
1158 
1159  if( module->m_Attributs != MOD_DEFAULT )
1160  {
1161  fprintf( aFile, "ATTRIBUTE" );
1162 
1163  if( module->m_Attributs & MOD_CMS )
1164  fprintf( aFile, " PAD_SMD" );
1165 
1166  if( module->m_Attributs & MOD_VIRTUAL )
1167  fprintf( aFile, " VIRTUAL" );
1168 
1169  fprintf( aFile, "\n" );
1170  }
1171 #endif
1172 
1173  // Silk outline; wildly interpreted by various importers:
1174  // CAM350 read it right but only closed shapes
1175  // ProntoPlace double-flip it (at least the pads are correct)
1176  // GerberTool usually get it right...
1177  for( PtStruct = module->GraphicalItemsList(); PtStruct; PtStruct = PtStruct->Next() )
1178  {
1179  switch( PtStruct->Type() )
1180  {
1181  case PCB_MODULE_TEXT_T:
1182 
1183  // If we wanted to export text, this is not the correct section
1184  break;
1185 
1186  case PCB_MODULE_EDGE_T:
1187  PtEdge = (EDGE_MODULE*) PtStruct;
1188  if( PtEdge->GetLayer() == F_SilkS
1189  || PtEdge->GetLayer() == B_SilkS )
1190  {
1191  switch( PtEdge->GetShape() )
1192  {
1193  case S_SEGMENT:
1194  fprintf( aFile, "LINE %g %g %g %g\n",
1195  (PtEdge->m_Start0.x) / SCALE_FACTOR,
1196  (Yaxis_sign * PtEdge->m_Start0.y) / SCALE_FACTOR,
1197  (PtEdge->m_End0.x) / SCALE_FACTOR,
1198  (Yaxis_sign * PtEdge->m_End0.y ) / SCALE_FACTOR );
1199  break;
1200 
1201  case S_CIRCLE:
1202  {
1203  int radius = KiROUND( GetLineLength( PtEdge->m_End0,
1204  PtEdge->m_Start0 ) );
1205  fprintf( aFile, "CIRCLE %g %g %g\n",
1206  PtEdge->m_Start0.x / SCALE_FACTOR,
1207  Yaxis_sign * PtEdge->m_Start0.y / SCALE_FACTOR,
1208  radius / SCALE_FACTOR );
1209  break;
1210  }
1211 
1212  case S_ARC:
1213  {
1214  int arcendx, arcendy;
1215  arcendx = PtEdge->m_End0.x - PtEdge->m_Start0.x;
1216  arcendy = PtEdge->m_End0.y - PtEdge->m_Start0.y;
1217  RotatePoint( &arcendx, &arcendy, -PtEdge->GetAngle() );
1218  arcendx += PtEdge->GetStart0().x;
1219  arcendy += PtEdge->GetStart0().y;
1220  if( Yaxis_sign == -1 )
1221  {
1222  // Flipping Y flips the arc direction too
1223  fprintf( aFile, "ARC %g %g %g %g %g %g\n",
1224  (arcendx) / SCALE_FACTOR,
1225  (Yaxis_sign * arcendy) / SCALE_FACTOR,
1226  (PtEdge->m_End0.x) / SCALE_FACTOR,
1227  (Yaxis_sign * PtEdge->GetEnd0().y) / SCALE_FACTOR,
1228  (PtEdge->GetStart0().x) / SCALE_FACTOR,
1229  (Yaxis_sign * PtEdge->GetStart0().y) / SCALE_FACTOR );
1230  }
1231  else
1232  {
1233  fprintf( aFile, "ARC %g %g %g %g %g %g\n",
1234  (PtEdge->GetEnd0().x) / SCALE_FACTOR,
1235  (Yaxis_sign * PtEdge->GetEnd0().y) / SCALE_FACTOR,
1236  (arcendx) / SCALE_FACTOR,
1237  (Yaxis_sign * arcendy) / SCALE_FACTOR,
1238  (PtEdge->GetStart0().x) / SCALE_FACTOR,
1239  (Yaxis_sign * PtEdge->GetStart0().y) / SCALE_FACTOR );
1240  }
1241  break;
1242  }
1243 
1244  case S_POLYGON:
1245  // Not exported (TODO)
1246  break;
1247 
1248  default:
1249  DisplayError( NULL, wxString::Format( "Type Edge Module %d invalid.", PtStruct->Type() ) );
1250  break;
1251  }
1252  }
1253  break;
1254 
1255  default:
1256  break;
1257  }
1258  }
1259 }
int GetFlag() const
Definition: class_module.h:202
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Function AllCuMask returns a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:639
static void CreateBoardSection(FILE *aFile, BOARD *aPcb)
KICAD_T Type() const
Function Type()
Definition: base_struct.h:198
#define DIM(x)
of elements in an array
Definition: macros.h:98
int GetLength() const
static int PadListSortByShape(const void *aRefptr, const void *aObjptr)
static void CreateShapesSection(FILE *aFile, BOARD *aPcb)
double GetLineLength(const wxPoint &aPointA, const wxPoint &aPointB)
Function GetLineLength returns the length of a line segment defined by aPointA and aPointB...
Definition: trigo.h:183
std::string FmtHex() const
Function FmtHex returns a hex string showing contents of this LSEQ.
Definition: lset.cpp:253
virtual LSET GetLayerSet() const override
Function GetLayerSet returns a "layer mask", which is a bitmap of all layers on which the TRACK segme...
This file is part of the common library TODO brief description.
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:107
Class LOCALE_IO is a class that can be instantiated within a scope in which you are expecting excepti...
Definition: common.h:166
static int ViaSort(const void *aRefptr, const void *aObjptr)
This file is part of the common library.
const wxPoint & GetPos0() const
EDA_RECT ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Function ComputeBoundingBox calculates the bounding box containing all board items (or board edge seg...
static void CreateRoutesSection(FILE *aFile, BOARD *aPcb)
void Flip(const wxPoint &aCentre) override
Function Flip Flip this object, i.e.
Class BOARD to handle a board.
static void CreateSignalsSection(FILE *aFile, BOARD *aPcb)
const wxPoint & GetPosition() const override
Definition: class_module.h:155
polygon (not yet used for tracks, but could be in microwave apps)
int GetTextWidth() const
Definition: eda_text.h:218
MODULE * Next() const
Definition: class_module.h:100
const wxPoint & GetEnd0() const
int GetCopperLayerCount() const
Function GetCopperLayerCount.
static double MapYTo(int aY)
Set for modules listed in the automatic insertion list (usually SMD footprints)
Definition: class_module.h:77
BOARD * GetBoard() const
const wxPoint & GetPos0() const
Definition: class_pad.h:176
const wxString & GetValue() const
Function GetValue.
Definition: class_module.h:447
DLIST< SEGZONE > m_Zone
Definition: class_board.h:247
void ExportToGenCAD(wxCommandEvent &event)
Function ExportToGenCAD creates a file in GenCAD 1.4 format from the current board.
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: kicad.cpp:65
usual segment : line with rounded ends
const wxString & GetDate() const
void SetSubRatsnest(int aSubRatsnest)
Definition: class_pad.h:475
EDA_ITEM * Next() const
Definition: base_struct.h:206
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
static int GencadOffsetY
void NORMALIZE_ANGLE_POS(T &Angle)
Definition: trigo.h:222
const wxSize & GetDrillSize() const
Definition: class_pad.h:188
PAD_SHAPE_T GetShape() const
Function GetShape.
Definition: class_pad.h:166
Class TITLE_BLOCK holds the information shown in the lower right corner of a plot, printout, or editing view.
static void CreateTracksInfoData(FILE *aFile, BOARD *aPcb)
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:106
const wxPoint & GetEnd() const
Definition: class_track.h:118
const wxPoint & GetAuxOrigin() const override
Function GetAuxOrigin returns the origin of the axis used for plotting and various exports...
static void CreateArtworksSection(FILE *aFile)
double GetTextAngle() const
Definition: eda_text.h:164
Functions relatives to tracks, vias and segments used to fill zones.
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:107
wxPoint m_End0
void vset(double *v, double x, double y, double z)
Definition: trackball.cpp:82
This file contains miscellaneous commonly used macros and functions.
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Function Seq returns an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:337
int StrPrintf(std::string *result, const char *format,...)
Function StrPrintf is like sprintf() but the output is appended to a std::string instead of to a char...
Definition: richio.cpp:75
const LIB_ID & GetFPID() const
Definition: class_module.h:164
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
static std::string GenCADLayerNameFlipped(int aCuCount, PCB_LAYER_ID aId)
static void CreateComponentsSection(FILE *aFile, BOARD *aPcb)
PCB_LAYER_ID
A quick note on layer IDs:
STROKE_T GetShape() const
Class LSET is a set of PCB_LAYER_IDs.
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
wxString GetBuildVersion()
Function GetBuildVersion Return the build version string.
static void CreatePadsShapesSection(FILE *aFile, BOARD *aPcb)
double GetOrientation() const
Definition: class_module.h:160
const wxString & GetFileName() const
Definition: class_board.h:234
int GetSubRatsnest() const
Function GetSubRatsnest.
Definition: class_pad.h:474
const wxString & GetRevision() const
const wxPoint & GetStart() const
Definition: class_track.h:121
const wxString & GetText() const
Function GetText returns the string associated with the text object.
Definition: eda_text.h:130
Arcs (with rounded ends)
static int Compare(const D_PAD *padref, const D_PAD *padcmp)
Function Compare compares two pads and return 0 if they are equal.
Definition: class_pad.cpp:1014
static const PCB_LAYER_ID gc_seq[]
LSET GetLayerSet() const override
Function GetLayerSet returns a "layer mask", which is a bitmap of all layers on which the TRACK segme...
Definition: class_pad.h:235
static int TrackListSortByNetcode(const void *refptr, const void *objptr)
D_PAD * Next() const
Definition: class_pad.h:106
const wxSize & GetSize() const
Definition: class_pad.h:182
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:533
int GetAttributes() const
Definition: class_module.h:197
class SEGZONE, a segment used to fill a zone area (segment on a copper layer)
Definition: typeinfo.h:109
int GetNet() const
Function GetNet.
unsigned GetPadCount() const
Function GetPadCount.
Class LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
static void FootprintWriteShape(FILE *File, MODULE *module)
void Compile_Ratsnest(wxDC *aDC, bool aDisplayStatus)
Function Compile_Ratsnest Create the entire board ratsnest.
Definition: ratsnest.cpp:57
default
Definition: class_module.h:76
int GetNetCode() const
Function GetNetCode.
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:105
static std::string GenCADLayerName(int aCuCount, PCB_LAYER_ID aId)
void NEGATE_AND_NORMALIZE_ANGLE_POS(T &Angle)
Definition: trigo.h:262
const TITLE_BLOCK & GetTitleBlock() const override
const std::vector< D_PAD * > GetPads()
Function GetPads returns a reference to a list of all the pads.
Class NETINFO_ITEM handles the data for a net.
Definition: class_netinfo.h:69
PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
TRACK * Next() const
Definition: class_track.h:98
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
double GetAngle() const
see class PGM_BASE
const wxPoint & GetStart0() const
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
int GetDrillValue() const
Function GetDrillValue "calculates" the drill value for vias (m-Drill if > 0, or default drill value ...
static bool CreateHeaderInfoData(FILE *aFile, PCB_EDIT_FRAME *frame)
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:169
static void CreateDevicesSection(FILE *aFile, BOARD *aPcb)
const wxString & GetReference() const
Function GetReference.
Definition: class_module.h:419
DLIST< MODULE > m_Modules
Definition: class_board.h:245
int GetWidth() const
Definition: class_track.h:115
Virtual component: when created by copper shapes on board (Like edge card connectors, mounting hole...)
Definition: class_module.h:79
double GetOrientation() const
Function GetOrientation returns the rotation angle of the pad in tenths of degrees, but soon degrees.
Definition: class_pad.h:214
std::string FmtBin() const
Function FmtBin returns a binary string showing contents of this LSEQ.
Definition: lset.cpp:229
NETINFO_ITEM * FindNet(int aNetcode) const
Function FindNet searches for a net with the given netcode.
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:151
static const double SCALE_FACTOR
UTF8 Format() const
Function Format.
Definition: lib_id.cpp:263
int GetTextHeight() const
Definition: eda_text.h:221
bool IsCopperLayer(LAYER_NUM aLayerId)
Function IsCopperLayer tests whether a layer is a copper layer.
static int GencadOffsetX
DLIST< BOARD_ITEM > & GraphicalItemsList()
Definition: class_module.h:137
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:108
DLIST< D_PAD > & PadsList()
Definition: class_module.h:134
DLIST< TRACK > m_Track
Definition: class_board.h:246
static std::string fmt_mask(LSET aSet)
bool cmp(const Point *a, const Point *b)
Definition: shapes.h:227
Module description (excepted pads)
const wxString & GetNetname() const
Function GetNetname.
wxPoint m_Start0
LSET GetEnabledLayers() const
Function GetEnabledLayers returns a bit-mask of all the layers that are enabled.
void StringPadName(wxString &text) const
Definition: class_pad.cpp:442
EDGE_MODULE class definition.
class DRAWSEGMENT, a segment not on copper layers
Definition: typeinfo.h:103
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:69
const wxPoint & GetOffset() const
Definition: class_pad.h:191
NETINFO_ITEM * GetNet() const
Function GetNet Returns NET_INFO object for a given item.
void SetFlag(int aFlag)
Definition: class_module.h:200
DLIST_ITERATOR_WRAPPER< BOARD_ITEM > Drawings()
Definition: class_board.h:251
unsigned GetNetCount() const
Function GetNetCount.
Definition: class_board.h:786
int m_Attributs
Flag bits ( see Mod_Attribut )
Definition: class_module.h:678
static double MapXTo(int aX)
VIA * GetFirstVia(TRACK *aTrk, const TRACK *aStopPoint=NULL)
Scan a track list for the first VIA o NULL if not found (or NULL passed)
Definition: class_track.h:490