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