KiCad PCB EDA Suite
specctra_export.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) 2007-2015 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
5  * Copyright (C) 2015-2017 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 
26 /* This source is a complement to specctra.cpp and implements the export to
27  specctra dsn file format. The specification for the grammar of the specctra
28  dsn file used to develop this code is given here:
29  http://tech.groups.yahoo.com/group/kicad-users/files/ then file "specctra.pdf"
30 
31  Also see the comments at the top of the specctra.cpp file itself.
32 */
33 
34 #include <wxPcbStruct.h>
35 #include <confirm.h> // DisplayError()
36 #include <gestfich.h> // EDA_FileSelector()
37 #include <trigo.h> // RotatePoint()
38 #include <macros.h>
39 
40 #include <set> // std::set
41 #include <map> // std::map
42 
43 #include <boost/utility.hpp> // boost::addressof()
44 
45 #include <class_board.h>
46 #include <class_module.h>
47 #include <class_edge_mod.h>
48 #include <class_track.h>
49 #include <class_zone.h>
50 #include <class_drawsegment.h>
51 #include <base_units.h>
53 
54 #include <collectors.h>
55 
57 
58 #include <specctra.h>
59 
60 using namespace DSN;
61 
62 
63 // Add .1 mil to the requested clearances as a safety margin.
64 // There has been disagreement about interpretation of clearance in the past
65 // between KiCad and Freerouter, so keep this safetyMargin until the
66 // disagreement is resolved and stable. Freerouter seems to be moving
67 // (protected) traces upon loading the DSN file, and even though it seems to sometimes
68 // add its own 0.1 to the clearances, I believe this is happening after
69 // the load process (and moving traces) so I am of the opinion this is
70 // still needed.
71 static const double safetyMargin = 0.1;
72 
73 
74 // see wxPcbStruct.h
75 void PCB_EDIT_FRAME::ExportToSpecctra( wxCommandEvent& event )
76 {
77  wxString fullFileName;
78  wxString dsn_ext = SpecctraDsnFileExtension;
79  wxString mask = SpecctraDsnFileWildcard();
80  wxFileName fn( GetBoard()->GetFileName() );
81 
82  fn.SetExt( dsn_ext );
83 
84  fullFileName = EDA_FILE_SELECTOR( _( "Specctra DSN File" ),
85  fn.GetPath(),
86  fn.GetFullName(),
87  dsn_ext,
88  mask,
89  this,
90  wxFD_SAVE | wxFD_OVERWRITE_PROMPT,
91  false );
92 
93  if( fullFileName == wxEmptyString )
94  return;
95 
96  ExportSpecctraFile( fullFileName );
97 }
98 
99 
100 bool PCB_EDIT_FRAME::ExportSpecctraFile( const wxString& aFullFilename )
101 {
102  SPECCTRA_DB db;
103  bool ok = true;
104  wxString errorText;
105 
106  BASE_SCREEN* screen = GetScreen();
107  bool wasModified = screen->IsModify();
108 
110 
111  LOCALE_IO toggle; // Switch the locale to standard C
112 
113  // DSN Images (=KiCad MODULES and pads) must be presented from the
114  // top view. So we temporarily flip any modules which are on the back
115  // side of the board to the front, and record this in the MODULE's flag field.
116  db.FlipMODULEs( GetBoard() );
117 
118  try
119  {
121  db.FromBOARD( GetBoard() );
122  db.ExportPCB( aFullFilename, true );
123 
124  // if an exception is thrown by FromBOARD or ExportPCB(), then
125  // ~SPECCTRA_DB() will close the file.
126  }
127  catch( const IO_ERROR& ioe )
128  {
129  ok = false;
130 
131  // copy the error string to safe place, ioe is in this scope only.
132  errorText = ioe.What();
133  }
134 
135  // done assuredly, even if an exception was thrown and caught.
136  db.RevertMODULEs( GetBoard() );
137 
138  // The two calls below to MODULE::Flip(), both set the
139  // modified flag, yet their actions cancel each other out, so it should
140  // be ok to clear the modify flag.
141  if( !wasModified )
142  screen->ClrModify();
143 
144  if( ok )
145  {
146  SetStatusText( wxString( _( "BOARD exported OK." ) ) );
147  }
148  else
149  {
150  DisplayErrorMessage( this,
151  _( "Unable to export, please fix and try again" ),
152  errorText );
153  }
154 
155  return ok;
156 }
157 
158 
159 namespace DSN {
160 
162 
163 // "specctra reported units" are what we tell the external router that our
164 // exported lengths are in.
165 
166 
172 static inline double scale( int kicadDist )
173 {
174  // nanometers to um
175  return kicadDist / ( IU_PER_MM / 1000.0 );
176 }
177 
178 
179 // / Convert integer internal units to float um
180 static inline double IU2um( int kicadDist )
181 {
182  return kicadDist * (1000.0 / IU_PER_MM);
183 }
184 
185 
186 static inline double mapX( int x )
187 {
188  return scale( x );
189 }
190 
191 
192 static inline double mapY( int y )
193 {
194  return -scale( y ); // make y negative, since it is increasing going down.
195 }
196 
197 
204 static POINT mapPt( const wxPoint& pt )
205 {
206  POINT ret;
207 
208  ret.x = mapX( pt.x );
209  ret.y = mapY( pt.y );
210  ret.FixNegativeZero();
211  return ret;
212 }
213 
214 
220 static bool isRoundKeepout( D_PAD* aPad )
221 {
222  if( aPad->GetShape()==PAD_SHAPE_CIRCLE )
223  {
224  if( aPad->GetDrillSize().x >= aPad->GetSize().x )
225  return true;
226 
227  if( !( aPad->GetLayerSet() & LSET::AllCuMask() ).any() )
228  return true;
229  }
230 
231  return false;
232 }
233 
234 
239 static PATH* makePath( const POINT& aStart, const POINT& aEnd, const std::string& aLayerName )
240 {
241  PATH* path = new PATH( 0, T_path );
242 
243  path->AppendPoint( aStart );
244  path->AppendPoint( aEnd );
245  path->SetLayerId( aLayerName.c_str() );
246  return path;
247 }
248 
249 
251 {
252  char name[256]; // padstack name builder
253  std::string uniqifier;
254 
255  // caller must do these checks before calling here.
256  wxASSERT( !isRoundKeepout( aPad ) );
257 
258  PADSTACK* padstack = new PADSTACK();
259 
260  int reportedLayers = 0; // how many in reported padstack
261  const char* layerName[MAX_CU_LAYERS];
262 
263  uniqifier = '[';
264 
265  static const LSET all_cu = LSET::AllCuMask();
266 
267  bool onAllCopperLayers = ( (aPad->GetLayerSet() & all_cu) == all_cu );
268 
269  if( onAllCopperLayers )
270  uniqifier += 'A'; // A for all layers
271 
272  const int copperCount = aBoard->GetCopperLayerCount();
273 
274  for( int layer=0; layer<copperCount; ++layer )
275  {
276  PCB_LAYER_ID kilayer = pcbLayer2kicad[layer];
277 
278  if( onAllCopperLayers || aPad->IsOnLayer( kilayer ) )
279  {
280  layerName[reportedLayers++] = layerIds[layer].c_str();
281 
282  if( !onAllCopperLayers )
283  {
284  if( layer == 0 )
285  uniqifier += 'T';
286  else if( layer == copperCount - 1 )
287  uniqifier += 'B';
288  else
289  uniqifier += char('0' + layer); // layer index char
290  }
291  }
292  }
293 
294  uniqifier += ']';
295 
296  POINT dsnOffset;
297 
298  if( aPad->GetOffset().x || aPad->GetOffset().y )
299  {
300  char offsetTxt[64];
301 
302  wxPoint offset( aPad->GetOffset().x, aPad->GetOffset().y );
303 
304  dsnOffset = mapPt( offset );
305 
306  // using '(' or ')' would cause padstack name to be quote wrapped,
307  // so use other brackets, and {} locks freerouter.
308  sprintf( offsetTxt, "[%.6g,%.6g]", dsnOffset.x, dsnOffset.y );
309 
310  uniqifier += offsetTxt;
311  }
312 
313  switch( aPad->GetShape() )
314  {
315  default:
316  case PAD_SHAPE_CIRCLE:
317  {
318  double diameter = scale( aPad->GetSize().x );
319 
320  for( int ndx=0; ndx<reportedLayers; ++ndx )
321  {
322  SHAPE* shape = new SHAPE( padstack );
323 
324  padstack->Append( shape );
325 
326  CIRCLE* circle = new CIRCLE( shape );
327 
328  shape->SetShape( circle );
329 
330  circle->SetLayerId( layerName[ndx] );
331  circle->SetDiameter( diameter );
332  circle->SetVertex( dsnOffset );
333  }
334 
335  snprintf( name, sizeof(name), "Round%sPad_%.6g_um",
336  uniqifier.c_str(), IU2um( aPad->GetSize().x ) );
337 
338  name[ sizeof(name) - 1 ] = 0;
339 
340  padstack->SetPadstackId( name );
341  }
342  break;
343 
344  case PAD_SHAPE_RECT:
345  {
346  double dx = scale( aPad->GetSize().x ) / 2.0;
347  double dy = scale( aPad->GetSize().y ) / 2.0;
348 
349  POINT lowerLeft( -dx, -dy );
350  POINT upperRight( dx, dy );
351 
352  lowerLeft += dsnOffset;
353  upperRight += dsnOffset;
354 
355  for( int ndx=0; ndx<reportedLayers; ++ndx )
356  {
357  SHAPE* shape = new SHAPE( padstack );
358 
359  padstack->Append( shape );
360 
361  RECTANGLE* rect = new RECTANGLE( shape );
362 
363  shape->SetShape( rect );
364 
365  rect->SetLayerId( layerName[ndx] );
366  rect->SetCorners( lowerLeft, upperRight );
367  }
368 
369  snprintf( name, sizeof(name), "Rect%sPad_%.6gx%.6g_um",
370  uniqifier.c_str(),
371  IU2um( aPad->GetSize().x ),
372  IU2um( aPad->GetSize().y ) );
373 
374  name[ sizeof(name) - 1 ] = 0;
375 
376  padstack->SetPadstackId( name );
377  }
378  break;
379 
380  case PAD_SHAPE_OVAL:
381  {
382  double dx = scale( aPad->GetSize().x ) / 2.0;
383  double dy = scale( aPad->GetSize().y ) / 2.0;
384  double dr = dx - dy;
385  double radius;
386  POINT pstart;
387  POINT pstop;
388 
389  if( dr >= 0 ) // oval is horizontal
390  {
391  radius = dy;
392 
393  pstart = POINT( -dr, 0.0 );
394  pstop = POINT( dr, 0.0 );
395  }
396  else // oval is vertical
397  {
398  radius = dx;
399  dr = -dr;
400 
401  pstart = POINT( 0.0, -dr );
402  pstop = POINT( 0.0, dr );
403  }
404 
405  pstart += dsnOffset;
406  pstop += dsnOffset;
407 
408  for( int ndx=0; ndx<reportedLayers; ++ndx )
409  {
410  SHAPE* shape;
411  PATH* path;
412  // see http://www.freerouting.net/usren/viewtopic.php?f=3&t=317#p408
413  shape = new SHAPE( padstack );
414 
415  padstack->Append( shape );
416  path = makePath( pstart, pstop, layerName[ndx] );
417  shape->SetShape( path );
418  path->aperture_width = 2.0 * radius;
419  }
420 
421  snprintf( name, sizeof(name), "Oval%sPad_%.6gx%.6g_um",
422  uniqifier.c_str(),
423  IU2um( aPad->GetSize().x ),
424  IU2um( aPad->GetSize().y ) );
425  name[ sizeof(name) - 1 ] = 0;
426 
427  padstack->SetPadstackId( name );
428  }
429  break;
430 
431  case PAD_SHAPE_TRAPEZOID:
432  {
433  double dx = scale( aPad->GetSize().x ) / 2.0;
434  double dy = scale( aPad->GetSize().y ) / 2.0;
435 
436  double ddx = scale( aPad->GetDelta().x ) / 2.0;
437  double ddy = scale( aPad->GetDelta().y ) / 2.0;
438 
439  // see class_pad_draw_functions.cpp which draws the trapezoid pad
440  POINT lowerLeft( -dx - ddy, -dy - ddx );
441  POINT upperLeft( -dx + ddy, +dy + ddx );
442  POINT upperRight( +dx - ddy, +dy - ddx );
443  POINT lowerRight( +dx + ddy, -dy + ddx );
444 
445  lowerLeft += dsnOffset;
446  upperLeft += dsnOffset;
447  upperRight += dsnOffset;
448  lowerRight += dsnOffset;
449 
450  for( int ndx=0; ndx<reportedLayers; ++ndx )
451  {
452  SHAPE* shape = new SHAPE( padstack );
453 
454  padstack->Append( shape );
455 
456  // a T_polygon exists as a PATH
457  PATH* polygon = new PATH( shape, T_polygon );
458 
459  shape->SetShape( polygon );
460 
461  polygon->SetLayerId( layerName[ndx] );
462 
463  polygon->AppendPoint( lowerLeft );
464  polygon->AppendPoint( upperLeft );
465  polygon->AppendPoint( upperRight );
466  polygon->AppendPoint( lowerRight );
467  }
468 
469  // this string _must_ be unique for a given physical shape
470  snprintf( name, sizeof(name), "Trapz%sPad_%.6gx%.6g_%c%.6gx%c%.6g_um",
471  uniqifier.c_str(), IU2um( aPad->GetSize().x ), IU2um( aPad->GetSize().y ),
472  aPad->GetDelta().x < 0 ? 'n' : 'p',
473  std::abs( IU2um( aPad->GetDelta().x )),
474  aPad->GetDelta().y < 0 ? 'n' : 'p',
475  std::abs( IU2um( aPad->GetDelta().y ) )
476  );
477  name[ sizeof(name)-1 ] = 0;
478 
479  padstack->SetPadstackId( name );
480  }
481  break;
482  }
483 
484  return padstack;
485 }
486 
487 
489 typedef std::map<wxString, int> PINMAP;
490 
491 
493 {
494  PINMAP pinmap;
495  wxString padName;
496 
497  PCB_TYPE_COLLECTOR moduleItems;
498 
499  // get all the MODULE's pads.
500  moduleItems.Collect( aModule, scanPADs );
501 
502  IMAGE* image = new IMAGE(0);
503 
504  image->image_id = aModule->GetFPID().Format().c_str();
505 
506  // from the pads, and make an IMAGE using collated padstacks.
507  for( int p=0; p < moduleItems.GetCount(); ++p )
508  {
509  D_PAD* pad = (D_PAD*) moduleItems[p];
510 
511  // see if this pad is a through hole with no copper on its perimeter
512  if( isRoundKeepout( pad ) )
513  {
514  double diameter = scale( pad->GetDrillSize().x );
515  POINT vertex = mapPt( pad->GetPos0() );
516 
517  int layerCount = aBoard->GetCopperLayerCount();
518 
519  for( int layer=0; layer<layerCount; ++layer )
520  {
521  KEEPOUT* keepout = new KEEPOUT( image, T_keepout );
522 
523  image->keepouts.push_back( keepout );
524 
525  CIRCLE* circle = new CIRCLE( keepout );
526 
527  keepout->SetShape( circle );
528 
529  circle->SetDiameter( diameter );
530  circle->SetVertex( vertex );
531  circle->SetLayerId( layerIds[layer].c_str() );
532  }
533  }
534  // else if() could there be a square keepout here?
535 
536  else
537  {
538  // Pads not on copper layers (i.e. only on tech layers) are ignored
539  // because they create invalid pads in .dsn file for freeroute
540  LSET mask_copper_layers = pad->GetLayerSet() & LSET::AllCuMask();
541 
542  if( !mask_copper_layers.any() )
543  continue;
544 
545  PADSTACK* padstack = makePADSTACK( aBoard, pad );
546  PADSTACKSET::iterator iter = padstackset.find( *padstack );
547 
548  if( iter != padstackset.end() )
549  {
550  // padstack is a duplicate, delete it and use the original
551  delete padstack;
552  padstack = (PADSTACK*) *iter.base(); // folklore, be careful here
553  }
554  else
555  {
556  padstackset.insert( padstack );
557  }
558 
559  PIN* pin = new PIN( image );
560 
561  padName = pad->GetName();
562  pin->pin_id = TO_UTF8( padName );
563 
564  if( padName!=wxEmptyString && pinmap.find( padName )==pinmap.end() )
565  {
566  pinmap[ padName ] = 0;
567  }
568  else // pad name is a duplicate within this module
569  {
570  char buf[32];
571 
572  int duplicates = ++pinmap[ padName ];
573 
574  sprintf( buf, "@%d", duplicates );
575 
576  pin->pin_id += buf; // append "@1" or "@2", etc. to pin name
577  }
578 
579  pin->kiNetCode = pad->GetNetCode();
580 
581  image->pins.push_back( pin );
582 
583  pin->padstack_id = padstack->padstack_id;
584 
585  double angle = pad->GetOrientationDegrees() - aModule->GetOrientationDegrees();
587  pin->SetRotation( angle );
588 
589  wxPoint pos( pad->GetPos0() );
590 
591  pin->SetVertex( mapPt( pos ) );
592  }
593  }
594 
595 #if 1 // enable image (outline) scopes.
596  static const KICAD_T scanEDGEs[] = { PCB_MODULE_EDGE_T, EOT };
597 
598  // get all the MODULE's EDGE_MODULEs and convert those to DSN outlines.
599  moduleItems.Collect( aModule, scanEDGEs );
600 
601  for( int i = 0; i<moduleItems.GetCount(); ++i )
602  {
603  EDGE_MODULE* graphic = (EDGE_MODULE*) moduleItems[i];
604  SHAPE* outline;
605  PATH* path;
606 
607  switch( graphic->GetShape() )
608  {
609  case S_SEGMENT:
610  outline = new SHAPE( image, T_outline );
611 
612  image->Append( outline );
613  path = new PATH( outline );
614 
615  outline->SetShape( path );
616  path->SetAperture( scale( graphic->GetWidth() ) );
617  path->SetLayerId( "signal" );
618  path->AppendPoint( mapPt( graphic->GetStart0() ) );
619  path->AppendPoint( mapPt( graphic->GetEnd0() ) );
620  break;
621 
622  case S_CIRCLE:
623  {
624  // this is best done by 4 QARC's but freerouter does not yet support QARCs.
625  // for now, support by using line segments.
626 
627  outline = new SHAPE( image, T_outline );
628 
629  image->Append( outline );
630  path = new PATH( outline );
631 
632  outline->SetShape( path );
633  path->SetAperture( scale( graphic->GetWidth() ) );
634  path->SetLayerId( "signal" );
635 
636  // Do the math using KiCad units, that way we stay out of the
637  // scientific notation range of floating point numbers in the
638  // DSN file. We do not parse scientific notation in our own
639  // lexer/beautifier, and the spec is not clear that this is
640  // required. Fixed point floats are all that should be needed.
641 
642  double radius = GetLineLength( graphic->GetStart(), graphic->GetEnd() );
643 
644  // better if evenly divisible into 360
645  const int DEGREE_INTERVAL = 18; // 18 means 20 line segments
646 
647  for( double radians = 0.0;
648  radians < 2 * M_PI;
649  radians += DEGREE_INTERVAL * M_PI / 180.0 )
650  {
651  wxPoint point( KiROUND( radius * cos( radians ) ),
652  KiROUND( radius * sin( radians ) ) );
653 
654  point += graphic->m_Start0; // an offset
655 
656  path->AppendPoint( mapPt( point ) );
657  }
658  }
659  break;
660 
661  case S_RECT:
662  case S_ARC:
663  default:
664  DBG( printf( "makeIMAGE(): unsupported shape %s\n",
665  TO_UTF8( BOARD_ITEM::ShowShape( graphic->GetShape() ) ) ); )
666  continue;
667  }
668  }
669 
670 #endif
671 
672  return image;
673 }
674 
675 
676 PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter, int aDrillDiameter,
677  int aTopLayer, int aBotLayer )
678 {
679  char name[48];
680  PADSTACK* padstack = new PADSTACK();
681  double dsnDiameter = scale( aCopperDiameter );
682 
683  for( int layer=aTopLayer; layer<=aBotLayer; ++layer )
684  {
685  SHAPE* shape = new SHAPE( padstack );
686 
687  padstack->Append( shape );
688 
689  CIRCLE* circle = new CIRCLE( shape );
690 
691  shape->SetShape( circle );
692 
693  circle->SetDiameter( dsnDiameter );
694  circle->SetLayerId( layerIds[layer].c_str() );
695  }
696 
697  snprintf( name, sizeof(name), "Via[%d-%d]_%.6g:%.6g_um",
698  aTopLayer, aBotLayer, dsnDiameter,
699  // encode the drill value into the name for later import
700  IU2um( aDrillDiameter )
701  );
702 
703  name[ sizeof(name) - 1 ] = 0;
704  padstack->SetPadstackId( name );
705 
706  return padstack;
707 }
708 
709 
711 {
712  PCB_LAYER_ID topLayerNum;
713  PCB_LAYER_ID botLayerNum;
714 
715  aVia->LayerPair( &topLayerNum, &botLayerNum );
716 
717  int topLayer = kicadLayer2pcb[topLayerNum];
718  int botLayer = kicadLayer2pcb[botLayerNum];
719 
720  if( topLayer > botLayer )
721  std::swap( topLayer, botLayer );
722 
723  return makeVia( aVia->GetWidth(), aVia->GetDrillValue(), topLayer, botLayer );
724 }
725 
726 
727 void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary )
728 {
729  wxString errMessage;
730  SHAPE_POLY_SET outlines;
731 
732  aBoard->GetBoardPolygonOutlines( outlines, &errMessage );
733 
734  for( int cnt = 0; cnt < outlines.OutlineCount(); cnt++ ) // Should be one outline
735  {
736  PATH* path = new PATH( boundary );
737  boundary->paths.push_back( path );
738  path->layer_id = "pcb";
739 
740  SHAPE_LINE_CHAIN& outline = outlines.Outline( cnt );
741 
742  for( int ii = 0; ii < outline.PointCount(); ii++ )
743  {
744  wxPoint pos( outline.Point( ii ).x, outline.Point( ii ).y );
745  path->AppendPoint( mapPt( pos ) );
746  }
747 
748  // Close polygon:
749  wxPoint pos0( outline.Point( 0 ).x, outline.Point( 0 ).y );
750  path->AppendPoint( mapPt( pos0 ) );
751 
752  // Generate holes as keepout:
753  for( int ii = 0; ii < outlines.HoleCount( cnt ); ii++ )
754  {
755  // emit a signal layers keepout for every interior polygon left...
756  KEEPOUT* keepout = new KEEPOUT( NULL, T_keepout );
757  PATH* poly_ko = new PATH( NULL, T_polygon );
758 
759  keepout->SetShape( poly_ko );
760  poly_ko->SetLayerId( "signal" );
761  pcb->structure->keepouts.push_back( keepout );
762 
763  SHAPE_LINE_CHAIN& hole = outlines.Hole( cnt, ii );
764 
765  for( int jj = 0; jj < hole.PointCount(); jj++ )
766  {
767  wxPoint pos( hole.Point( jj ).x, hole.Point( jj ).y );
768  poly_ko->AppendPoint( mapPt( pos ) );
769  }
770 
771  // Close polygon:
772  wxPoint pos( hole.Point( 0 ).x, hole.Point( 0 ).y );
773  poly_ko->AppendPoint( mapPt( pos ) );
774  }
775  }
776 
777  if( !errMessage.IsEmpty() )
778  wxLogMessage( errMessage );
779 }
780 
781 
782 typedef std::set<std::string> STRINGSET;
783 typedef std::pair<STRINGSET::iterator, bool> STRINGSET_PAIR;
784 
785 
787 {
788  PCB_TYPE_COLLECTOR items;
789 
790  static const KICAD_T scanMODULEs[] = { PCB_MODULE_T, EOT };
791 
792  // Not all boards are exportable. Check that all reference Ids are unique.
793  // Unless they are unique, we cannot import the session file which comes
794  // back to us later from the router.
795  {
796  items.Collect( aBoard, scanMODULEs );
797 
798  STRINGSET refs; // holds module reference designators
799 
800  for( int i=0; i<items.GetCount(); ++i )
801  {
802  MODULE* module = (MODULE*) items[i];
803 
804  if( module->GetReference() == wxEmptyString )
805  {
806  THROW_IO_ERROR( wxString::Format( _( "Component with value of \"%s\" has empty reference id." ),
807  GetChars( module->GetValue() ) ) );
808  }
809 
810  // if we cannot insert OK, that means the reference has been seen before.
811  STRINGSET_PAIR refpair = refs.insert( TO_UTF8( module->GetReference() ) );
812  if( !refpair.second ) // insert failed
813  {
814  THROW_IO_ERROR( wxString::Format( _( "Multiple components have identical reference IDs of \"%s\"." ),
815  GetChars( module->GetReference() ) ) );
816  }
817  }
818  }
819 
820  if( !pcb )
822 
823  //-----<layer_descriptor>-----------------------------------------------
824  {
825  // specctra wants top physical layer first, then going down to the
826  // bottom most physical layer in physical sequence.
827  // @question : why does KiCad not display layers in that order?
828 
829  buildLayerMaps( aBoard );
830 
831  int layerCount = aBoard->GetCopperLayerCount();
832 
833  for( int pcbNdx=0; pcbNdx<layerCount; ++pcbNdx )
834  {
835  LAYER* layer = new LAYER( pcb->structure );
836 
837  pcb->structure->layers.push_back( layer );
838 
839  layer->name = layerIds[pcbNdx];
840 
841  DSN_T layerType;
842 
843  switch( aBoard->GetLayerType( pcbLayer2kicad[pcbNdx] ) )
844  {
845  default:
846  case LT_SIGNAL: layerType = T_signal; break;
847  case LT_POWER: layerType = T_power; break;
848 
849 #if 1 // Freerouter does not support type "mixed", only signal and power.
850  // Remap "mixed" to "signal".
851  case LT_MIXED: layerType = T_signal; break;
852 #else
853  case LT_MIXED: layerType = T_mixed; break;
854 #endif
855  case LT_JUMPER: layerType = T_jumper; break;
856  }
857 
858  layer->layer_type = layerType;
859 
860  layer->properties.push_back( PROPERTY() );
861  PROPERTY* property = &layer->properties.back();
862  property->name = "index";
863  char temp[32];
864  sprintf( temp, "%d", pcbNdx );
865  property->value = temp;
866  }
867  }
868 
869  // a space in a quoted token is NOT a terminator, true establishes this.
871 
872  //-----<unit_descriptor> & <resolution_descriptor>--------------------
873  {
874  // tell freerouter to use "tenths of micrometers",
875  // which is 100 nm resolution. Possibly more resolution is possible
876  // in freerouter, but it would need testing.
877 
878  pcb->unit->units = T_um;
879  pcb->resolution->units = T_um;
880  pcb->resolution->value = 10; // tenths of a um
881  // pcb->resolution->value = 1000; // "thousandths of a um" (i.e. "nm")
882  }
883 
884  //-----<boundary_descriptor>------------------------------------------
885  {
886  // Because fillBOUNDARY() can throw an exception, we link in an
887  // empty boundary so the BOUNDARY does not get lost in the event of
888  // of an exception.
889  BOUNDARY* boundary = new BOUNDARY( 0 );
890 
891  pcb->structure->SetBOUNDARY( boundary );
892  fillBOUNDARY( aBoard, boundary );
893  }
894 
895 
896  //-----<rules>--------------------------------------------------------
897  {
898  char rule[80];
899  NETCLASSPTR defaultClass = aBoard->GetDesignSettings().GetDefault();
900 
901  int defaultTrackWidth = defaultClass->GetTrackWidth();
902  int defaultClearance = defaultClass->GetClearance();
903 
904  double clearance = scale( defaultClearance );
905 
906  STRINGS& rules = pcb->structure->rules->rules;
907 
908  sprintf( rule, "(width %.6g)", scale( defaultTrackWidth ) );
909  rules.push_back( rule );
910 
911  sprintf( rule, "(clearance %.6g)", clearance + safetyMargin );
912  rules.push_back( rule );
913 
914  // On a high density board (a board with 4 mil tracks, 4 mil spacing)
915  // a typical solder mask clearance will be 2-3 mils.
916  // This exposes 2 to 3 mils of bare board around each pad, and would
917  // leave only 1 to 2 mils of solder mask between the solder mask's boundary
918  // to the edge of any trace within "clearance" of the pad. So we need at least
919  // 2 mils *extra* clearance for traces which would come near a pad on
920  // a different net. So if the baseline trace to trace clearance was say 4 mils, then
921  // the SMD to trace clearance should be at least 6 mils.
922  double default_smd = clearance + safetyMargin;
923 
924  if( default_smd <= 6.0 )
925  default_smd = 6.0;
926 
927  sprintf( rule, "(clearance %.6g (type default_smd))", default_smd );
928 
929  rules.push_back( rule );
930 
931  /* see: http://www.freerouting.net/usren/viewtopic.php?f=5&t=339#p474
932  sprintf( rule, "(clearance %.6g (type pad_to_turn_gap))", clearance + safetyMargin );
933  rules.push_back( rule );
934 
935  sprintf( rule, "(clearance %.6g (type smd_to_turn_gap))", clearance + safetyMargin );
936  rules.push_back( rule );
937 
938  sprintf( rule, "(clearance %.6g (type via_via))", clearance + safetyMargin );
939  rules.push_back( rule );
940 
941  sprintf( rule, "(clearance %.6g (type via_smd))", clearance + safetyMargin );
942  rules.push_back( rule );
943 
944  sprintf( rule, "(clearance %.6g (type via_pin))", clearance + safetyMargin );
945  rules.push_back( rule );
946 
947  sprintf( rule, "(clearance %.6g (type pin_pin))", clearance + safetyMargin );
948  rules.push_back( rule );
949 
950  sprintf( rule, "(clearance %.6g (type smd_pin))", clearance + safetyMargin );
951  rules.push_back( rule );
952  */
953 
954  // Pad to pad spacing on a single SMT part can be closer than our
955  // clearance, we don't want freerouter complaining about that, so
956  // output a significantly smaller pad to pad clearance to freerouter.
957  clearance = scale( defaultClearance ) / 4;
958 
959  sprintf( rule, "(clearance %.6g (type smd_smd))", clearance );
960  rules.push_back( rule );
961  }
962 
963 
964  //-----<zone containers (not keepout areas) become planes>--------------------------------
965  // Note: only zones are output here, keepout areas be be created later
966  {
967  int netlessZones = 0;
968 
969  static const KICAD_T scanZONEs[] = { PCB_ZONE_AREA_T, EOT };
970  items.Collect( aBoard, scanZONEs );
971 
972  for( int i = 0; i<items.GetCount(); ++i )
973  {
974  ZONE_CONTAINER* item = (ZONE_CONTAINER*) items[i];
975 
976  if( item->GetIsKeepout() )
977  continue;
978 
979  // Currently, we export only copper layers
980  if( ! IsCopperLayer( item->GetLayer() ) )
981  continue;
982 
983  COPPER_PLANE* plane = new COPPER_PLANE( pcb->structure );
984 
985  pcb->structure->planes.push_back( plane );
986 
987  PATH* mainPolygon = new PATH( plane, T_polygon );
988 
989  plane->SetShape( mainPolygon );
990 
991  plane->name = TO_UTF8( item->GetNetname() );
992 
993  if( plane->name.size() == 0 )
994  {
995  char name[32];
996 
997  // This is one of those no connection zones, netcode=0, and it has no name.
998  // Create a unique, bogus netname.
999  NET* no_net = new NET( pcb->network );
1000 
1001  sprintf( name, "@:no_net_%d", netlessZones++ );
1002  no_net->net_id = name;
1003 
1004  // add the bogus net name to network->nets.
1005  pcb->network->nets.push_back( no_net );
1006 
1007  // use the bogus net name in the netless zone.
1008  plane->name = no_net->net_id;
1009  }
1010 
1011  mainPolygon->layer_id = layerIds[ kicadLayer2pcb[ item->GetLayer() ] ];
1012 
1013  // Handle the main outlines
1014  SHAPE_POLY_SET::ITERATOR iterator;
1015  for( iterator = item->IterateWithHoles(); iterator; iterator++ )
1016  {
1017  wxPoint point( iterator->x, iterator->y );
1018  mainPolygon->AppendPoint( mapPt(point) );
1019 
1020  // this was the end of the main polygon
1021  if( iterator.IsEndContour() )
1022  break;
1023  }
1024 
1025  WINDOW* window = 0;
1026  PATH* cutout = 0;
1027 
1028  bool isStartContour = true;
1029 
1030  // handle the cutouts
1031  for( iterator++; iterator; iterator++ )
1032  {
1033  if( isStartContour )
1034  {
1035  window = new WINDOW( plane );
1036 
1037  plane->AddWindow( window );
1038 
1039  cutout = new PATH( window, T_polygon );
1040 
1041  window->SetShape( cutout );
1042 
1043  cutout->layer_id = layerIds[ kicadLayer2pcb[ item->GetLayer() ] ];
1044  }
1045 
1046  // If the point in this iteration is the last of the contour, the next iteration
1047  // will start with a new contour.
1048  isStartContour = iterator.IsEndContour();
1049 
1050  wxASSERT( window );
1051  wxASSERT( cutout );
1052 
1053  wxPoint point(iterator->x, iterator->y );
1054  cutout->AppendPoint( mapPt(point) );
1055  }
1056  }
1057  }
1058 
1059  //-----<zone containers flagged keepout areas become keepout>--------------------------------
1060  {
1061  static const KICAD_T scanZONEs[] = { PCB_ZONE_AREA_T, EOT };
1062  items.Collect( aBoard, scanZONEs );
1063 
1064  for( int i=0; i<items.GetCount(); ++i )
1065  {
1066  ZONE_CONTAINER* item = (ZONE_CONTAINER*) items[i];
1067 
1068  if( ! item->GetIsKeepout() )
1069  continue;
1070 
1071  // keepout areas have a type. types are
1072  // T_place_keepout, T_via_keepout, T_wire_keepout,
1073  // T_bend_keepout, T_elongate_keepout, T_keepout.
1074  // Pcbnew knows only T_keepout, T_via_keepout and T_wire_keepout
1075  DSN_T keepout_type;
1076 
1077  if( item->GetDoNotAllowVias() && item->GetDoNotAllowTracks() )
1078  keepout_type = T_keepout;
1079  else if( item->GetDoNotAllowVias() )
1080  keepout_type = T_via_keepout;
1081  else if( item->GetDoNotAllowTracks() )
1082  keepout_type = T_wire_keepout;
1083  else
1084  keepout_type = T_keepout;
1085 
1086  // Now, build keepout polygon on each copper layer where the item
1087  // keepout is living (keepout zones can live on many copper layers)
1088  const int copperCount = aBoard->GetCopperLayerCount();
1089 
1090  for( int layer = 0; layer < copperCount; layer++ )
1091  {
1092  if( layer == copperCount-1)
1093  layer = B_Cu;
1094 
1095  if( !item->IsOnLayer( PCB_LAYER_ID( layer ) ) )
1096  continue;
1097 
1098  KEEPOUT* keepout = new KEEPOUT( pcb->structure, keepout_type );
1099  pcb->structure->keepouts.push_back( keepout );
1100 
1101  PATH* mainPolygon = new PATH( keepout, T_polygon );
1102  keepout->SetShape( mainPolygon );
1103 
1104  mainPolygon->layer_id = layerIds[ kicadLayer2pcb[ layer ] ];
1105 
1106  // Handle the main outlines
1107  SHAPE_POLY_SET::ITERATOR iterator;
1108  for( iterator = item->IterateWithHoles(); iterator; iterator++ )
1109  {
1110  wxPoint point( iterator->x, iterator->y );
1111  mainPolygon->AppendPoint( mapPt(point) );
1112 
1113  // this was the end of the main polygon
1114  if( iterator.IsEndContour() )
1115  break;
1116  }
1117 
1118  WINDOW* window = 0;
1119  PATH* cutout = 0;
1120 
1121  bool isStartContour = true;
1122 
1123  // handle the cutouts
1124  for( iterator++; iterator; iterator++ )
1125  {
1126  if( isStartContour )
1127  {
1128  window = new WINDOW( keepout );
1129  keepout->AddWindow( window );
1130 
1131  cutout = new PATH( window, T_polygon );
1132 
1133  window->SetShape( cutout );
1134 
1135  cutout->layer_id = layerIds[ kicadLayer2pcb[ item->GetLayer() ] ];
1136  }
1137 
1138  isStartContour = iterator.IsEndContour();
1139 
1140  wxASSERT( window );
1141  wxASSERT( cutout );
1142 
1143  wxPoint point(iterator->x, iterator->y );
1144  cutout->AppendPoint( mapPt(point) );
1145  }
1146  }
1147  }
1148  }
1149 
1150  //-----<build the images, components, and netlist>-----------------------
1151  {
1152  PIN_REF empty( pcb->network );
1153 
1154  std::string componentId;
1155 
1156  // find the highest numbered netCode within the board.
1157  int highestNetCode = aBoard->GetNetCount() - 1;
1158 
1159  deleteNETs();
1160 
1161  // expand the net vector to highestNetCode+1, setting empty to NULL
1162  nets.resize( highestNetCode + 1, NULL );
1163 
1164  // skip netcode = 0
1165  for( unsigned i = 1; i<nets.size(); ++i )
1166  nets[i] = new NET( pcb->network );
1167 
1168  for( unsigned ii = 0; ii < aBoard->GetNetCount(); ii++ )
1169  {
1170  NETINFO_ITEM* net = aBoard->FindNet( ii );
1171  int netcode = net->GetNet();
1172 
1173  if( netcode > 0 )
1174  nets[ netcode ]->net_id = TO_UTF8( net->GetNetname() );
1175  }
1176 
1177  items.Collect( aBoard, scanMODULEs );
1178 
1179  padstackset.clear();
1180 
1181  for( int m = 0; m<items.GetCount(); ++m )
1182  {
1183  MODULE* module = (MODULE*) items[m];
1184 
1185  IMAGE* image = makeIMAGE( aBoard, module );
1186 
1187  componentId = TO_UTF8( module->GetReference() );
1188 
1189  // create a net list entry for all the actual pins in the image
1190  // for the current module. location of this code is critical
1191  // because we fabricated some pin names to ensure unique-ness
1192  // of pin names within a module, do not move this code because
1193  // the life of this 'IMAGE* image' is not necessarily long. The
1194  // exported netlist will have some fabricated pin names in it.
1195  // If you don't like fabricated pin names, then make sure all pads
1196  // within your MODULEs are uniquely named!
1197  for( unsigned p = 0; p<image->pins.size(); ++p )
1198  {
1199  PIN* pin = &image->pins[p];
1200 
1201  int netcode = pin->kiNetCode;
1202 
1203  if( netcode > 0 )
1204  {
1205  NET* net = nets[netcode];
1206 
1207  net->pins.push_back( empty );
1208 
1209  PIN_REF& pin_ref = net->pins.back();
1210 
1211  pin_ref.component_id = componentId;
1212  pin_ref.pin_id = pin->pin_id;
1213  }
1214  }
1215 
1216 
1217  IMAGE* registered = pcb->library->LookupIMAGE( image );
1218 
1219  if( registered != image )
1220  {
1221  // If our new 'image' is not a unique IMAGE, delete it.
1222  // and use the registered one, known as 'image' after this.
1223  delete image;
1224  image = registered;
1225  }
1226 
1227  COMPONENT* comp = pcb->placement->LookupCOMPONENT( image->GetImageId() );
1228 
1229  PLACE* place = new PLACE( comp );
1230 
1231  comp->places.push_back( place );
1232 
1233  place->SetRotation( module->GetOrientationDegrees() );
1234  place->SetVertex( mapPt( module->GetPosition() ) );
1235  place->component_id = componentId;
1236  place->part_number = TO_UTF8( module->GetValue() );
1237 
1238  // module is flipped from bottom side, set side to T_back
1239  if( module->GetFlag() )
1240  {
1241  double angle = 180.0 - module->GetOrientationDegrees();
1242  NORMALIZE_ANGLE_DEGREES_POS( angle );
1243  place->SetRotation( angle );
1244 
1245  place->side = T_back;
1246  }
1247  }
1248 
1249  // copy the SPECCTRA_DB::padstackset to the LIBRARY. Since we are
1250  // removing, do not increment the iterator
1251  for( PADSTACKSET::iterator i = padstackset.begin(); i!=padstackset.end();
1252  i = padstackset.begin() )
1253  {
1254  PADSTACKSET::auto_type ps = padstackset.release( i );
1255  PADSTACK* padstack = ps.release();
1256 
1257  pcb->library->AddPadstack( padstack );
1258  }
1259 
1260  // copy our SPECCTRA_DB::nets to the pcb->network
1261  for( unsigned n = 1; n<nets.size(); ++n )
1262  {
1263  NET* net = nets[n];
1264 
1265  if( net->pins.size() )
1266  {
1267  // give ownership to pcb->network
1268  pcb->network->nets.push_back( net );
1269  nets[n] = 0;
1270  }
1271  }
1272  }
1273 
1274 
1275  //-----< output vias used in netclasses >-----------------------------------
1276  {
1277  NETCLASSES& nclasses = aBoard->GetDesignSettings().m_NetClasses;
1278 
1279  // Assume the netclass vias are all the same kind of thru, blind, or buried vias.
1280  // This is in lieu of either having each netclass via have its own layer pair in
1281  // the netclass dialog, or such control in the specctra export dialog.
1282 
1283 
1284  // if( aBoard->GetDesignSettings().m_CurrentViaType == VIA_THROUGH )
1285  {
1286  m_top_via_layer = 0; // first specctra cu layer is number zero.
1287  m_bot_via_layer = aBoard->GetCopperLayerCount()-1;
1288  }
1289  /*
1290  else
1291  {
1292  // again, should be in the BOARD:
1293  topLayer = kicadLayer2pcb[ GetScreen()->m_Route_Layer_TOP ];
1294  botLayer = kicadLayer2pcb[ GetScreen()->m_Route_Layer_BOTTOM ];
1295  }
1296  */
1297 
1298  // Add the via from the Default netclass first. The via container
1299  // in pcb->library preserves the sequence of addition.
1300 
1301  NETCLASSPTR netclass = nclasses.GetDefault();
1302 
1303  PADSTACK* via = makeVia( netclass->GetViaDiameter(), netclass->GetViaDrill(),
1305 
1306  // we AppendVia() this first one, there is no way it can be a duplicate,
1307  // the pcb->library via container is empty at this point. After this,
1308  // we'll have to use LookupVia().
1309  wxASSERT( pcb->library->vias.size() == 0 );
1310  pcb->library->AppendVia( via );
1311 
1312 #if 0
1313  // I've seen no way to make stock vias useable by freerouter. Also the
1314  // zero based diameter was leading to duplicates in the LookupVia() function.
1315  // User should use netclass based vias when going to freerouter.
1316 
1317  // Output the stock vias, but preserve uniqueness in the via container by
1318  // using LookupVia().
1319  for( unsigned i = 0; i < aBoard->m_ViasDimensionsList.size(); ++i )
1320  {
1321  int viaSize = aBoard->m_ViasDimensionsList[i].m_Diameter;
1322  int viaDrill = aBoard->m_ViasDimensionsList[i].m_Drill;
1323 
1324  via = makeVia( viaSize, viaDrill,
1326 
1327  // maybe add 'via' to the library, but only if unique.
1328  PADSTACK* registered = pcb->library->LookupVia( via );
1329 
1330  if( registered != via )
1331  delete via;
1332  }
1333 #endif
1334 
1335  // set the "spare via" index at the start of the
1336  // pcb->library->spareViaIndex = pcb->library->vias.size();
1337 
1338  // output the non-Default netclass vias
1339  for( NETCLASSES::iterator nc = nclasses.begin(); nc != nclasses.end(); ++nc )
1340  {
1341  netclass = nc->second;
1342 
1343  via = makeVia( netclass->GetViaDiameter(), netclass->GetViaDrill(),
1345 
1346  // maybe add 'via' to the library, but only if unique.
1347  PADSTACK* registered = pcb->library->LookupVia( via );
1348 
1349  if( registered != via )
1350  delete via;
1351  }
1352  }
1353 
1354 
1355 #if 1 // do existing wires and vias
1356 
1357  //-----<create the wires from tracks>-----------------------------------
1358  {
1359  // export all of them for now, later we'll decide what controls we need
1360  // on this.
1361  static const KICAD_T scanTRACKs[] = { PCB_TRACE_T, EOT };
1362 
1363  items.Collect( aBoard, scanTRACKs );
1364 
1365  std::string netname;
1366  WIRING* wiring = pcb->wiring;
1367  PATH* path = 0;
1368 
1369  int old_netcode = -1;
1370  int old_width = -1;
1371  LAYER_NUM old_layer = UNDEFINED_LAYER;
1372 
1373  for( int i=0; i<items.GetCount(); ++i )
1374  {
1375  TRACK* track = (TRACK*) items[i];
1376 
1377  int netcode = track->GetNetCode();
1378 
1379  if( netcode == 0 )
1380  continue;
1381 
1382  if( old_netcode != netcode ||
1383  old_width != track->GetWidth() ||
1384  old_layer != track->GetLayer() ||
1385  (path && path->points.back() != mapPt(track->GetStart()) )
1386  )
1387  {
1388  old_width = track->GetWidth();
1389  old_layer = track->GetLayer();
1390 
1391  if( old_netcode != netcode )
1392  {
1393  old_netcode = netcode;
1394  NETINFO_ITEM* net = aBoard->FindNet( netcode );
1395  wxASSERT( net );
1396  netname = TO_UTF8( net->GetNetname() );
1397  }
1398 
1399  WIRE* wire = new WIRE( wiring );
1400 
1401  wiring->wires.push_back( wire );
1402  wire->net_id = netname;
1403 
1404  wire->wire_type = T_protect; // @todo, this should be configurable
1405 
1406  LAYER_NUM kiLayer = track->GetLayer();
1407  int pcbLayer = kicadLayer2pcb[kiLayer];
1408 
1409  path = new PATH( wire );
1410 
1411  wire->SetShape( path );
1412 
1413  path->layer_id = layerIds[pcbLayer];
1414  path->aperture_width = scale( old_width );
1415 
1416  path->AppendPoint( mapPt( track->GetStart() ) );
1417  }
1418 
1419  if( path ) // Should not occur
1420  path->AppendPoint( mapPt( track->GetEnd() ) );
1421  }
1422  }
1423 
1424 
1425  //-----<export the existing real BOARD instantiated vias>-----------------
1426  {
1427  // Export all vias, once per unique size and drill diameter combo.
1428  static const KICAD_T scanVIAs[] = { PCB_VIA_T, EOT };
1429 
1430  items.Collect( aBoard, scanVIAs );
1431 
1432  for( int i = 0; i<items.GetCount(); ++i )
1433  {
1434  ::VIA* via = (::VIA*) items[i];
1435  wxASSERT( via->Type() == PCB_VIA_T );
1436 
1437  int netcode = via->GetNetCode();
1438 
1439  if( netcode == 0 )
1440  continue;
1441 
1442  PADSTACK* padstack = makeVia( via );
1443  PADSTACK* registered = pcb->library->LookupVia( padstack );
1444 
1445  // if the one looked up is not our padstack, then delete our padstack
1446  // since it was a duplicate of one already registered.
1447  if( padstack != registered )
1448  {
1449  delete padstack;
1450  }
1451 
1452  WIRE_VIA* dsnVia = new WIRE_VIA( pcb->wiring );
1453 
1454  pcb->wiring->wire_vias.push_back( dsnVia );
1455 
1456  dsnVia->padstack_id = registered->padstack_id;
1457  dsnVia->vertexes.push_back( mapPt( via->GetPosition() ) );
1458 
1459  NETINFO_ITEM* net = aBoard->FindNet( netcode );
1460  wxASSERT( net );
1461 
1462  dsnVia->net_id = TO_UTF8( net->GetNetname() );
1463 
1464  dsnVia->via_type = T_protect; // @todo, this should be configurable
1465  }
1466  }
1467 
1468 #endif // do existing wires and vias
1469 
1470  //-----<via_descriptor>-------------------------------------------------
1471  {
1472  // The pcb->library will output <padstack_descriptors> which is a combined
1473  // list of part padstacks and via padstacks. specctra dsn uses the
1474  // <via_descriptors> to say which of those padstacks are vias.
1475 
1476  // Output the vias in the padstack list here, by name only. This must
1477  // be done after exporting existing vias as WIRE_VIAs.
1478  VIA* vias = pcb->structure->via;
1479 
1480  for( unsigned viaNdx = 0; viaNdx < pcb->library->vias.size(); ++viaNdx )
1481  {
1482  vias->AppendVia( pcb->library->vias[viaNdx].padstack_id.c_str() );
1483  }
1484  }
1485 
1486 
1487  //-----<output NETCLASSs>----------------------------------------------------
1488  NETCLASSES& nclasses = aBoard->GetDesignSettings().m_NetClasses;
1489 
1490  exportNETCLASS( nclasses.GetDefault(), aBoard );
1491 
1492  for( NETCLASSES::iterator nc = nclasses.begin(); nc != nclasses.end(); ++nc )
1493  {
1494  NETCLASSPTR netclass = nc->second;
1495  exportNETCLASS( netclass, aBoard );
1496  }
1497 }
1498 
1499 
1500 void SPECCTRA_DB::exportNETCLASS( NETCLASSPTR aNetClass, BOARD* aBoard )
1501 {
1502  /* From page 11 of specctra spec:
1503  *
1504  * Routing and Placement Rule Hierarchies
1505  *
1506  * Routing and placement rules can be defined at multiple levels of design
1507  * specification. When a routing or placement rule is defined for an object at
1508  * multiple levels, a predefined routing or placement precedence order
1509  * automatically determines which rule to apply to the object. The routing rule
1510  * precedence order is
1511  *
1512  * pcb < layer < class < class layer < group_set < group_set layer < net <
1513  * net layer < group < group layer < fromto < fromto layer < class_class <
1514  * class_class layer < padstack < region < class region < net region <
1515  * class_class region
1516  *
1517  * A pcb rule (global rule for the PCB design) has the lowest precedence in the
1518  * hierarchy. A class-to-class region rule has the highest precedence. Rules
1519  * set at one level of the hierarchy override conflicting rules set at lower
1520  * levels. The placement rule precedence order is
1521  *
1522  * pcb < image_set < image < component < super cluster < room <
1523  * room_image_set < family_family < image_image
1524  *
1525  * A pcb rule (global rule for the PCB design) has the lowest precedence in the
1526  * hierarchy. An image-to-image rule has the highest precedence. Rules set at
1527  * one level of the hierarchy override conflicting rules set at lower levels.
1528  */
1529 
1530  char text[256];
1531 
1532  CLASS* clazz = new CLASS( pcb->network );
1533 
1534  pcb->network->classes.push_back( clazz );
1535 
1536  // freerouter creates a class named 'default' anyway, and if we
1537  // try and use that, we end up with two 'default' via rules so use
1538  // something else as the name of our default class.
1539  clazz->class_id = TO_UTF8( aNetClass->GetName() );
1540 
1541  for( NETCLASS::iterator net = aNetClass->begin(); net != aNetClass->end(); ++net )
1542  clazz->net_ids.push_back( TO_UTF8( *net ) );
1543 
1544  clazz->rules = new RULE( clazz, T_rule );
1545 
1546  // output the track width.
1547  int trackWidth = aNetClass->GetTrackWidth();
1548  sprintf( text, "(width %.6g)", scale( trackWidth ) );
1549  clazz->rules->rules.push_back( text );
1550 
1551  // output the clearance.
1552  int clearance = aNetClass->GetClearance();
1553  sprintf( text, "(clearance %.6g)", scale( clearance ) + safetyMargin );
1554  clazz->rules->rules.push_back( text );
1555 
1556  if( aNetClass->GetName() == NETCLASS::Default )
1557  {
1558  clazz->class_id = "kicad_default";
1559  }
1560 
1561  // the easiest way to get the via name is to create a via (which generates
1562  // the name internal to the PADSTACK), and then grab the name and then
1563  // delete the via. There are not that many netclasses so
1564  // this should never become a performance issue.
1565 
1566  PADSTACK* via = makeVia( aNetClass->GetViaDiameter(), aNetClass->GetViaDrill(),
1568 
1569  snprintf( text, sizeof(text), "(use_via %s)", via->GetPadstackId().c_str() );
1570  clazz->circuit.push_back( text );
1571 
1572  delete via;
1573 }
1574 
1575 
1577 {
1578  for( MODULE* module = aBoard->m_Modules; module; module = module->Next() )
1579  {
1580  module->SetFlag( 0 );
1581  if( module->GetLayer() == B_Cu )
1582  {
1583  module->Flip( module->GetPosition() );
1584  module->SetFlag( 1 );
1585  }
1586  }
1587 
1588  modulesAreFlipped = true;
1589 }
1590 
1591 
1593 {
1594  if( !modulesAreFlipped )
1595  return;
1596 
1597  // DSN Images (=KiCad MODULES and pads) must be presented from the
1598  // top view. Restore those that were flipped.
1599  for( MODULE* module = aBoard->m_Modules; module; module = module->Next() )
1600  {
1601  if( module->GetFlag() )
1602  {
1603  module->Flip( module->GetPosition() );
1604  module->SetFlag( 0 );
1605  }
1606  }
1607 
1608  modulesAreFlipped = false;
1609 }
1610 
1611 } // namespace DSN
int GetFlag() const
Definition: class_module.h:222
DSN_T units
Definition: specctra.h:405
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:646
Class VIA corresponds to the in the specctra dsn spec.
Definition: specctra.h:1011
void FixNegativeZero()
Function FixNegativeZero will change negative zero to positive zero in the IEEE floating point storag...
Definition: specctra.h:136
int GetCount() const
Function GetCount returns the number of objects in the list.
void ExportToSpecctra(wxCommandEvent &event)
Function ExporttoSPECCTRA Ask for a filename and call ExportSpecctraFile to export the current BOARD ...
Class PIN_REF corresponds to the definition in the specctra dsn spec.
Definition: specctra.h:2428
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:60
static wxString ShowShape(STROKE_T aShape)
Function ShowShape converts the enum STROKE_T integer value to a wxString.
bool space_in_quoted_tokens
Definition: specctra.h:372
void SetAperture(double aWidth)
Definition: specctra.h:607
std::string pin_id
Definition: specctra.h:1929
void buildLayerMaps(BOARD *aBoard)
Function buildLayerMaps creates a few data translation structures for layer name and number mapping b...
Definition: specctra.cpp:74
static bool isRoundKeepout(D_PAD *aPad)
Function isRoundKeepout decides if the pad is a copper-less through hole which needs to be made into ...
std::map< wxString, int > PINMAP
data type used to ensure unique-ness of pin names, holding (wxString and int)
NETCLASSPTR GetDefault() const
Function GetDefault.
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:191
Class NET corresponds to a in the DSN spec.
Definition: specctra.h:2568
This source file implements export and import capabilities to the specctra dsn file format...
Definition: specctra.cpp:62
COPPER_PLANES planes
Definition: specctra.h:1543
STRINGS circuit
circuit descriptor list
Definition: specctra.h:2730
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
double y
Definition: specctra.h:97
std::string net_id
Definition: specctra.h:2572
Implementation of conversion functions that require both schematic and board internal units...
This file is part of the common library.
KEEPOUTS keepouts
Definition: specctra.h:1997
std::string component_id
Definition: specctra.h:2430
Definition: hash_eda.h:42
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, wxString *aErrorText=NULL)
Function GetBoardPolygonOutlines Extracts the board outlines and build a closed polygon from lines...
T
enum T contains all this lexer's tokens.
RULE * rules
Definition: specctra.h:1539
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
static const double safetyMargin
int PointCount() const
Function PointCount()
PINS pins
Definition: specctra.h:1992
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Function IsOnLayer tests to see if this object is on the given layer.
Definition: class_zone.cpp:268
Class BOARD to handle a board.
const wxPoint & GetPosition() const override
Definition: class_module.h:175
PADSTACKSET padstackset
Definition: specctra.h:3638
std::string part_number
Definition: specctra.h:1688
PADSTACKS vias
Definition: specctra.h:2239
static POINT mapPt(const wxPoint &pt)
Function mapPt converts a KiCad point into a DSN file point.
MODULE * Next() const
Definition: class_module.h:120
const wxPoint & GetEnd0() const
static double IU2um(int kicadDist)
IMAGE * LookupIMAGE(IMAGE *aImage)
Function LookupIMAGE will add the image only if one exactly like it does not already exist in the ima...
Definition: specctra.h:2317
int GetCopperLayerCount() const
Function GetCopperLayerCount.
class ZONE_CONTAINER, a zone area
Definition: typeinfo.h:102
int HoleCount(int aOutline) const
Returns the number of holes in a given outline
virtual PCB_LAYER_ID GetLayer() const override
Function GetLayer returns the primary layer this item is on.
Definition: class_zone.cpp:178
void SetLayerId(const char *aLayerId)
Definition: specctra.h:602
void SetLayerId(const char *aLayerId)
Definition: specctra.h:753
POINTS vertexes
Definition: specctra.h:2962
int kiNetCode
KiCad netcode.
Definition: specctra.h:1932
void fillBOUNDARY(BOARD *aBoard, BOUNDARY *aBoundary)
Function fillBOUNDARY makes the board perimeter for the DSN file by filling the BOUNDARY element in t...
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Returns the reference to aHole-th hole in the aIndex-th outline
UNIT_RES * resolution
Definition: specctra.h:3141
Classes to handle copper zones.
const wxPoint & GetPos0() const
Definition: class_pad.h:263
const wxString & GetValue() const
Function GetValue.
Definition: class_module.h:467
bool IsModify() const
usual segment : line with rounded ends
void AppendPoint(const POINT &aPoint)
Definition: specctra.h:595
class D_PAD, a pad in a footprint
Definition: typeinfo.h:90
Class CLASS corresponds to the in the specctra spec.
Definition: specctra.h:2721
iterator end()
PLACES places
Definition: specctra.h:1746
void NORMALIZE_ANGLE_DEGREES_POS(double &Angle)
Definition: trigo.h:259
double x
Definition: specctra.h:96
void SetPCB(PCB *aPcb)
Function SetPCB deletes any existing PCB and replaces it with the given one.
Definition: specctra.h:3884
void SetRotation(double aRotation)
Definition: specctra.h:1944
STRUCTURE * structure
Definition: specctra.h:3143
int OutlineCount() const
Returns the number of outlines in the set
const wxSize & GetDrillSize() const
Definition: class_pad.h:275
WIRING * wiring
Definition: specctra.h:3147
void SetLayerId(const char *aLayerId)
Definition: specctra.h:455
PAD_SHAPE_T GetShape() const
Function GetShape.
Definition: class_pad.h:216
static PCB * MakePCB()
Function MakePCB makes a PCB with all the default ELEMs and parts on the heap.
Definition: specctra.cpp:3463
#define abs(a)
Definition: auxiliary.h:84
std::string net_id
Definition: specctra.h:2963
std::string class_id
Definition: specctra.h:2725
void SetVertex(const POINT &aPoint)
Definition: specctra.h:1950
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:94
std::string layer_id
Definition: specctra.h:580
const wxPoint & GetEnd() const
Definition: class_track.h:120
DSN_T via_type
Definition: specctra.h:2965
IMAGE * makeIMAGE(BOARD *aBoard, MODULE *aModule)
Function makeIMAGE allocates an IMAGE on the heap and creates all the PINs according to the D_PADs in...
search types array terminator (End Of Types)
Definition: typeinfo.h:82
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_StructType.
Definition: typeinfo.h:78
void ExportPCB(wxString aFilename, bool aNameChange=false)
Function ExportPCB writes the internal PCB instance out as a SPECTRA DSN format file.
Definition: specctra.cpp:3438
void FlipMODULEs(BOARD *aBoard)
Function FlipMODULEs flips the modules which are on the back side of the board to the front...
Class RULE corresponds to the in the specctra dsn spec.
Definition: specctra.h:492
void SetVertex(const POINT &aVertex)
Definition: specctra.h:1718
std::set< std::string > STRINGSET
Functions relatives to tracks, vias and segments used to fill zones.
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
bool IsEndContour() const
Function IsEndContour.
This file contains miscellaneous commonly used macros and functions.
void SetShape(ELEM *aShape)
Definition: specctra.h:852
PADSTACK * makePADSTACK(BOARD *aBoard, D_PAD *aPad)
Function makePADSTACK creates a PADSTACK which matches the given pad.
static const KICAD_T scanPADs[]
Definition: specctra.h:3636
Class PATH supports both the and the per the specctra dsn spec...
Definition: specctra.h:576
bool GetIsKeepout() const
Accessors to parameters used in Keepout zones:
Definition: class_zone.h:602
std::pair< STRINGSET::iterator, bool > STRINGSET_PAIR
void exportNETCLASS(std::shared_ptr< NETCLASS > aNetClass, BOARD *aBoard)
Function exportNETCLASS exports aNetClass to the DSN file.
const std::string & GetPadstackId()
Definition: specctra.h:2139
const LIB_ID & GetFPID() const
Definition: class_module.h:184
#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
void SynchronizeNetsAndNetClasses()
Function SynchronizeNetsAndNetClasses copies NETCLASS info to each NET, based on NET membership in a ...
DSN_T layer_type
one of: T_signal, T_power, T_mixed, T_jumper
Definition: specctra.h:1181
NETCLASS_MAP::iterator iterator
segment with non rounded ends
class MODULE, a footprint
Definition: typeinfo.h:89
void SetShape(ELEM *aShape)
Definition: specctra.h:929
WIRES wires
Definition: specctra.h:3098
STRINGSET::iterator iterator
PCB_LAYER_ID
A quick note on layer IDs:
STROKE_T GetShape() const
Class LSET is a set of PCB_LAYER_IDs.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString aExtraInfo)
Function DisplayErrorMessage displays an error message with aMessage.
Definition: confirm.cpp:87
iterator begin()
Class NETCLASSES is a container for NETCLASS instances.
std::string image_id
Definition: specctra.h:1983
std::string name
Definition: specctra.h:1180
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
double GetOrientationDegrees() const
Definition: class_module.h:181
void AddWindow(WINDOW *aWindow)
Definition: specctra.h:944
Class COPPER_PLANE corresponds to a in the specctra dsn spec.
Definition: specctra.h:1325
static const char Default[]
the name of the default NETCLASS
void deleteNETs()
Function deleteNETs deletes all the NETs that may be in here.
Definition: specctra.h:3810
std::string padstack_id
Definition: specctra.h:2961
Class SHAPE_POLY_SET.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Returns the reference to aIndex-th outline in the set
DSN_T side
Definition: specctra.h:1665
Class BASE_SCREEN handles how to draw a screen (a board, a schematic ...)
const wxPoint & GetStart() const
Definition: class_track.h:123
Arcs (with rounded ends)
Class PLACE implements the in the specctra dsn spec.
Definition: specctra.h:1659
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:395
wxString EDA_FILE_SELECTOR(const wxString &aTitle, const wxString &aPath, const wxString &aFileName, const wxString &aExtension, const wxString &aWildcard, wxWindow *aParent, int aStyle, const bool aKeepWorkingDirectory, const wxPoint &aPosition, wxString *aMruPath)
Function EDA_FILE_SELECTOR.
Definition: gestfich.cpp:82
The common library.
void AddPadstack(PADSTACK *aPadstack)
Definition: specctra.h:2254
const wxSize & GetSize() const
Definition: class_pad.h:269
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:532
std::string component_id
reference designator
Definition: specctra.h:1663
const wxString & GetName() const
Definition: class_pad.h:190
Class PADSTACK holds either a via or a pad definition.
Definition: specctra.h:2098
void Append(ELEM *aElem)
Definition: specctra.h:321
WIRE_VIAS wire_vias
Definition: specctra.h:3099
int m_top_via_layer
specctra cu layers, 0 based index:
Definition: specctra.h:3644
std::vector< std::string > STRINGS
Definition: specctra.h:158
Definition: hash_eda.h:43
Class SPECCTRA_DB holds a DSN data tree, usually coming from a DSN file.
Definition: specctra.h:3607
int GetNet() const
Function GetNet.
CLASSLIST classes
Definition: specctra.h:2812
static PATH * makePath(const POINT &aStart, const POINT &aEnd, const std::string &aLayerName)
Function makePath creates a PATH element with a single straight line, a pair of vertices.
std::vector< int > kicadLayer2pcb
maps BOARD layer number to PCB layer numbers
Definition: specctra.h:3625
COMPONENT * LookupCOMPONENT(const std::string &imageName)
Function LookupCOMPONENT looks up a COMPONENT by name.
Definition: specctra.h:1817
void Collect(BOARD_ITEM *aBoard, const KICAD_T aScanList[])
Collect BOARD_ITEM objects using this class's Inspector method, which does the collection.
Definition: collectors.cpp:475
std::string padstack_id
Definition: specctra.h:1926
PARSER * parser
Definition: specctra.h:3140
void SetRotation(double aRotation)
Definition: specctra.h:1725
int LAYER_NUM
Type LAYER_NUM can be replaced with int and removed.
LIBRARY * library
Definition: specctra.h:3145
std::string GetImageId()
Definition: specctra.h:2025
BOARD * GetBoard()
int GetNetCode() const
Function GetNetCode.
Class SHAPE corresponds to the "(shape ..)" element in the specctra dsn spec.
Definition: specctra.h:1863
bool modulesAreFlipped
Definition: specctra.h:3618
Class NETINFO_ITEM handles the data for a net.
Definition: class_netinfo.h:69
void RevertMODULEs(BOARD *aBoard)
Function RevertMODULEs flips the modules which were on the back side of the board back to the back...
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
PADSTACK * LookupVia(PADSTACK *aVia)
Function LookupVia will add the via only if one exactly like it does not already exist in the padstac...
Definition: specctra.h:2372
Class COMPONENT implements the in the specctra dsn spec.
Definition: specctra.h:1739
bool GetDoNotAllowTracks() const
Definition: class_zone.h:605
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
Struct POINT is a holder for a point in the SPECCTRA DSN coordinate system.
Definition: specctra.h:94
void FromBOARD(BOARD *aBoard)
Function FromBOARD adds the entire BOARD to the PCB but does not write it out.
const wxString & GetNetname() const
Function GetNetname.
Class WIRE corresponds to in the specctra dsn spec.
Definition: specctra.h:2847
Class to handle a graphic segment.
const wxPoint & GetStart0() const
PATHS paths
Definition: specctra.h:654
const wxString SpecctraDsnFileExtension
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
void SetCorners(const POINT &aPoint0, const POINT &aPoint1)
Definition: specctra.h:460
bool GetDoNotAllowVias() const
Definition: class_zone.h:604
STRINGS layerIds
indexed by PCB layer number
Definition: specctra.h:3622
void AppendVia(PADSTACK *aVia)
Function AppendVia adds aVia to the internal via container.
Definition: specctra.h:2347
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:169
const wxString & GetReference() const
Function GetReference.
Definition: class_module.h:439
POINTS points
Definition: specctra.h:583
DLIST< MODULE > m_Modules
Definition: class_board.h:245
Class SHAPE_LINE_CHAIN.
int GetWidth() const
Definition: class_track.h:117
SHAPE_POLY_SET::ITERATOR IterateWithHoles()
Function IterateWithHoles returns an iterator to visit all points of the zone's main outline with hol...
Definition: class_zone.h:434
PLACEMENT * placement
Definition: specctra.h:3144
const char * c_str() const
Definition: utf8.h:107
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
static double mapY(int y)
RULE * rules
Definition: specctra.h:2732
Class ITERATOR_TEMPLATE.
NETCLASSPTR GetDefault() const
Function GetDefault.
static double mapX(int x)
const wxSize & GetDelta() const
Definition: class_pad.h:272
void SetShape(ELEM *aShape)
Definition: specctra.h:2888
static bool empty(const wxTextEntryBase *aCtrl)
static double scale(int kicadDist)
Function scale converts a distance from PCBNEW internal units to the reported specctra dsn units in f...
double aperture_width
Definition: specctra.h:581
NETINFO_ITEM * FindNet(int aNetcode) const
Function FindNet searches for a net with the given netcode.
void SetBOUNDARY(BOUNDARY *aBoundary)
Definition: specctra.h:1580
int GetWidth() const
std::string padstack_id
Definition: specctra.h:2104
UTF8 Format() const
Definition: lib_id.cpp:263
const char * name
void AppendVia(const char *aViaName)
Definition: specctra.h:1025
bool IsCopperLayer(LAYER_NUM aLayerId)
Function IsCopperLayer tests whether a layer is a copper layer.
UNIT_RES * unit
Definition: specctra.h:3142
VECTOR2I & Point(int aIndex)
Function Point()
LAYERS layers
Definition: specctra.h:1531
wxString SpecctraDsnFileWildcard()
PIN_REFS pins
Definition: specctra.h:2577
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
Class WIRE_VIA corresponds to in the specctra dsn spec.
Definition: specctra.h:2957
#define DBG(x)
Definition: fctsys.h:33
void SetVertex(const POINT &aVertex)
Definition: specctra.h:763
Module description (excepted pads)
const wxString & GetNetname() const
Function GetNetname.
wxPoint m_Start0
std::string pin_id
Definition: specctra.h:2431
DSN_T wire_type
Definition: specctra.h:2862
Collect all BOARD_ITEM objects of a given set of KICAD_T type(s).
Definition: collectors.h:544
std::vector< PCB_LAYER_ID > pcbLayer2kicad
maps PCB layer number to BOARD layer numbers
Definition: specctra.h:3628
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Function IsOnLayer tests to see if this object is on the given layer.
Definition: class_pad.h:637
DSN_T Type() const
Definition: specctra.h:231
PROPERTIES properties
Definition: specctra.h:1188
STRINGS net_ids
Definition: specctra.h:2727
EDGE_MODULE class definition.
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
Class KEEPOUT is used for and .
Definition: specctra.h:884
std::string name
Definition: specctra.h:889
NETWORK * network
Definition: specctra.h:3146
std::vector< NET * > nets
we don't want ownership here permanently, so we don't use boost::ptr_vector
Definition: specctra.h:3641
void SetPadstackId(const char *aPadstackId)
Definition: specctra.h:2151
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:47
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
LAYER_T GetLayerType(PCB_LAYER_ID aLayer) const
Function GetLayerType returns the type of the copper layer given by aLayer.
void SetDiameter(double aDiameter)
Definition: specctra.h:758
double GetOrientationDegrees() const
Definition: class_pad.h:376
Class WIRING corresponds to in the specctra dsn spec.
Definition: specctra.h:3093
const wxPoint & GetOffset() const
Definition: class_pad.h:278
std::string net_id
Definition: specctra.h:2860
NETCLASSES m_NetClasses
List of current netclasses. There is always the default netclass.
PADSTACK * makeVia(int aCopperDiameter, int aDrillDiameter, int aTopLayer, int aBotLayer)
Function makeVia makes a round through hole PADSTACK using the given KiCad diameter in deci-mils...
unsigned GetNetCount() const
Function GetNetCount.
Definition: class_board.h:772
bool ExportSpecctraFile(const wxString &aFullFilename)
Function ExportSpecctraFile will export the current BOARD to a specctra dsn file. ...
STRINGS rules
rules are saved in std::string form.
Definition: specctra.h:496
KEEPOUTS keepouts
Definition: specctra.h:1541