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