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  // skip netcode = 0
1344  for( unsigned i = 1; i<nets.size(); ++i )
1345  nets[i] = new NET( pcb->network );
1346 
1347  for( unsigned ii = 0; ii < aBoard->GetNetCount(); ii++ )
1348  {
1349  NETINFO_ITEM* net = aBoard->FindNet( ii );
1350  int netcode = net->GetNet();
1351 
1352  if( netcode > 0 )
1353  nets[ netcode ]->net_id = TO_UTF8( net->GetNetname() );
1354  }
1355 
1356  items.Collect( aBoard, scanMODULEs );
1357 
1358  padstackset.clear();
1359 
1360  for( int m = 0; m<items.GetCount(); ++m )
1361  {
1362  MODULE* module = (MODULE*) items[m];
1363 
1364  IMAGE* image = makeIMAGE( aBoard, module );
1365 
1366  componentId = TO_UTF8( module->GetReference() );
1367 
1368  // create a net list entry for all the actual pins in the image
1369  // for the current module. location of this code is critical
1370  // because we fabricated some pin names to ensure unique-ness
1371  // of pin names within a module, do not move this code because
1372  // the life of this 'IMAGE* image' is not necessarily long. The
1373  // exported netlist will have some fabricated pin names in it.
1374  // If you don't like fabricated pin names, then make sure all pads
1375  // within your MODULEs are uniquely named!
1376  for( unsigned p = 0; p<image->pins.size(); ++p )
1377  {
1378  PIN* pin = &image->pins[p];
1379 
1380  int netcode = pin->kiNetCode;
1381 
1382  if( netcode > 0 )
1383  {
1384  NET* net = nets[netcode];
1385 
1386  net->pins.push_back( empty );
1387 
1388  PIN_REF& pin_ref = net->pins.back();
1389 
1390  pin_ref.component_id = componentId;
1391  pin_ref.pin_id = pin->pin_id;
1392  }
1393  }
1394 
1395 
1396  IMAGE* registered = pcb->library->LookupIMAGE( image );
1397 
1398  if( registered != image )
1399  {
1400  // If our new 'image' is not a unique IMAGE, delete it.
1401  // and use the registered one, known as 'image' after this.
1402  delete image;
1403  image = registered;
1404  }
1405 
1406  COMPONENT* comp = pcb->placement->LookupCOMPONENT( image->GetImageId() );
1407 
1408  PLACE* place = new PLACE( comp );
1409 
1410  comp->places.push_back( place );
1411 
1412  place->SetRotation( module->GetOrientationDegrees() );
1413  place->SetVertex( mapPt( module->GetPosition() ) );
1414  place->component_id = componentId;
1415  place->part_number = TO_UTF8( module->GetValue() );
1416 
1417  // module is flipped from bottom side, set side to T_back
1418  if( module->GetFlag() )
1419  {
1420  double angle = 180.0 - module->GetOrientationDegrees();
1421  NORMALIZE_ANGLE_DEGREES_POS( angle );
1422  place->SetRotation( angle );
1423 
1424  place->side = T_back;
1425  }
1426  }
1427 
1428  // copy the SPECCTRA_DB::padstackset to the LIBRARY. Since we are
1429  // removing, do not increment the iterator
1430  for( PADSTACKSET::iterator i = padstackset.begin(); i!=padstackset.end();
1431  i = padstackset.begin() )
1432  {
1433  PADSTACKSET::auto_type ps = padstackset.release( i );
1434  PADSTACK* padstack = ps.release();
1435 
1436  pcb->library->AddPadstack( padstack );
1437  }
1438 
1439  // copy our SPECCTRA_DB::nets to the pcb->network
1440  for( unsigned n = 1; n<nets.size(); ++n )
1441  {
1442  NET* net = nets[n];
1443 
1444  if( net->pins.size() )
1445  {
1446  // give ownership to pcb->network
1447  pcb->network->nets.push_back( net );
1448  nets[n] = 0;
1449  }
1450  }
1451  }
1452 
1453 
1454  //-----< output vias used in netclasses >-----------------------------------
1455  {
1456  NETCLASSES& nclasses = aBoard->GetDesignSettings().m_NetClasses;
1457 
1458  // Assume the netclass vias are all the same kind of thru, blind, or buried vias.
1459  // This is in lieu of either having each netclass via have its own layer pair in
1460  // the netclass dialog, or such control in the specctra export dialog.
1461 
1462 
1463  // if( aBoard->GetDesignSettings().m_CurrentViaType == VIA_THROUGH )
1464  {
1465  m_top_via_layer = 0; // first specctra cu layer is number zero.
1466  m_bot_via_layer = aBoard->GetCopperLayerCount()-1;
1467  }
1468  /*
1469  else
1470  {
1471  // again, should be in the BOARD:
1472  topLayer = kicadLayer2pcb[ GetScreen()->m_Route_Layer_TOP ];
1473  botLayer = kicadLayer2pcb[ GetScreen()->m_Route_Layer_BOTTOM ];
1474  }
1475  */
1476 
1477  // Add the via from the Default netclass first. The via container
1478  // in pcb->library preserves the sequence of addition.
1479 
1480  NETCLASSPTR netclass = nclasses.GetDefault();
1481 
1482  PADSTACK* via = makeVia( netclass->GetViaDiameter(), netclass->GetViaDrill(),
1484 
1485  // we AppendVia() this first one, there is no way it can be a duplicate,
1486  // the pcb->library via container is empty at this point. After this,
1487  // we'll have to use LookupVia().
1488  wxASSERT( pcb->library->vias.size() == 0 );
1489  pcb->library->AppendVia( via );
1490 
1491 #if 0
1492  // I've seen no way to make stock vias useable by freerouter. Also the
1493  // zero based diameter was leading to duplicates in the LookupVia() function.
1494  // User should use netclass based vias when going to freerouter.
1495 
1496  // Output the stock vias, but preserve uniqueness in the via container by
1497  // using LookupVia().
1498  for( unsigned i = 0; i < aBoard->m_ViasDimensionsList.size(); ++i )
1499  {
1500  int viaSize = aBoard->m_ViasDimensionsList[i].m_Diameter;
1501  int viaDrill = aBoard->m_ViasDimensionsList[i].m_Drill;
1502 
1503  via = makeVia( viaSize, viaDrill,
1505 
1506  // maybe add 'via' to the library, but only if unique.
1507  PADSTACK* registered = pcb->library->LookupVia( via );
1508 
1509  if( registered != via )
1510  delete via;
1511  }
1512 #endif
1513 
1514  // set the "spare via" index at the start of the
1515  // pcb->library->spareViaIndex = pcb->library->vias.size();
1516 
1517  // output the non-Default netclass vias
1518  for( NETCLASSES::iterator nc = nclasses.begin(); nc != nclasses.end(); ++nc )
1519  {
1520  netclass = nc->second;
1521 
1522  via = makeVia( netclass->GetViaDiameter(), netclass->GetViaDrill(),
1524 
1525  // maybe add 'via' to the library, but only if unique.
1526  PADSTACK* registered = pcb->library->LookupVia( via );
1527 
1528  if( registered != via )
1529  delete via;
1530  }
1531  }
1532 
1533 
1534 #if 1 // do existing wires and vias
1535 
1536  //-----<create the wires from tracks>-----------------------------------
1537  {
1538  // export all of them for now, later we'll decide what controls we need
1539  // on this.
1540  static const KICAD_T scanTRACKs[] = { PCB_TRACE_T, EOT };
1541 
1542  items.Collect( aBoard, scanTRACKs );
1543 
1544  std::string netname;
1545  WIRING* wiring = pcb->wiring;
1546  PATH* path = 0;
1547 
1548  int old_netcode = -1;
1549  int old_width = -1;
1550  LAYER_NUM old_layer = UNDEFINED_LAYER;
1551 
1552  for( int i=0; i<items.GetCount(); ++i )
1553  {
1554  TRACK* track = (TRACK*) items[i];
1555 
1556  int netcode = track->GetNetCode();
1557 
1558  if( netcode == 0 )
1559  continue;
1560 
1561  if( old_netcode != netcode ||
1562  old_width != track->GetWidth() ||
1563  old_layer != track->GetLayer() ||
1564  (path && path->points.back() != mapPt(track->GetStart()) )
1565  )
1566  {
1567  old_width = track->GetWidth();
1568  old_layer = track->GetLayer();
1569 
1570  if( old_netcode != netcode )
1571  {
1572  old_netcode = netcode;
1573  NETINFO_ITEM* net = aBoard->FindNet( netcode );
1574  wxASSERT( net );
1575  netname = TO_UTF8( net->GetNetname() );
1576  }
1577 
1578  WIRE* wire = new WIRE( wiring );
1579 
1580  wiring->wires.push_back( wire );
1581  wire->net_id = netname;
1582 
1583  wire->wire_type = T_protect; // @todo, this should be configurable
1584 
1585  LAYER_NUM kiLayer = track->GetLayer();
1586  int pcbLayer = kicadLayer2pcb[kiLayer];
1587 
1588  path = new PATH( wire );
1589 
1590  wire->SetShape( path );
1591 
1592  path->layer_id = layerIds[pcbLayer];
1593  path->aperture_width = scale( old_width );
1594 
1595  path->AppendPoint( mapPt( track->GetStart() ) );
1596  }
1597 
1598  if( path ) // Should not occur
1599  path->AppendPoint( mapPt( track->GetEnd() ) );
1600  }
1601  }
1602 
1603 
1604  //-----<export the existing real BOARD instantiated vias>-----------------
1605  {
1606  // Export all vias, once per unique size and drill diameter combo.
1607  static const KICAD_T scanVIAs[] = { PCB_VIA_T, EOT };
1608 
1609  items.Collect( aBoard, scanVIAs );
1610 
1611  for( int i = 0; i<items.GetCount(); ++i )
1612  {
1613  ::VIA* via = (::VIA*) items[i];
1614  wxASSERT( via->Type() == PCB_VIA_T );
1615 
1616  int netcode = via->GetNetCode();
1617 
1618  if( netcode == 0 )
1619  continue;
1620 
1621  PADSTACK* padstack = makeVia( via );
1622  PADSTACK* registered = pcb->library->LookupVia( padstack );
1623 
1624  // if the one looked up is not our padstack, then delete our padstack
1625  // since it was a duplicate of one already registered.
1626  if( padstack != registered )
1627  {
1628  delete padstack;
1629  }
1630 
1631  WIRE_VIA* dsnVia = new WIRE_VIA( pcb->wiring );
1632 
1633  pcb->wiring->wire_vias.push_back( dsnVia );
1634 
1635  dsnVia->padstack_id = registered->padstack_id;
1636  dsnVia->vertexes.push_back( mapPt( via->GetPosition() ) );
1637 
1638  NETINFO_ITEM* net = aBoard->FindNet( netcode );
1639  wxASSERT( net );
1640 
1641  dsnVia->net_id = TO_UTF8( net->GetNetname() );
1642 
1643  dsnVia->via_type = T_protect; // @todo, this should be configurable
1644  }
1645  }
1646 
1647 #endif // do existing wires and vias
1648 
1649  //-----<via_descriptor>-------------------------------------------------
1650  {
1651  // The pcb->library will output <padstack_descriptors> which is a combined
1652  // list of part padstacks and via padstacks. specctra dsn uses the
1653  // <via_descriptors> to say which of those padstacks are vias.
1654 
1655  // Output the vias in the padstack list here, by name only. This must
1656  // be done after exporting existing vias as WIRE_VIAs.
1657  VIA* vias = pcb->structure->via;
1658 
1659  for( unsigned viaNdx = 0; viaNdx < pcb->library->vias.size(); ++viaNdx )
1660  {
1661  vias->AppendVia( pcb->library->vias[viaNdx].padstack_id.c_str() );
1662  }
1663  }
1664 
1665 
1666  //-----<output NETCLASSs>----------------------------------------------------
1667  NETCLASSES& nclasses = aBoard->GetDesignSettings().m_NetClasses;
1668 
1669  exportNETCLASS( nclasses.GetDefault(), aBoard );
1670 
1671  for( NETCLASSES::iterator nc = nclasses.begin(); nc != nclasses.end(); ++nc )
1672  {
1673  NETCLASSPTR netclass = nc->second;
1674  exportNETCLASS( netclass, aBoard );
1675  }
1676 }
1677 
1678 
1679 void SPECCTRA_DB::exportNETCLASS( const NETCLASSPTR& aNetClass, BOARD* aBoard )
1680 {
1681  /* From page 11 of specctra spec:
1682  *
1683  * Routing and Placement Rule Hierarchies
1684  *
1685  * Routing and placement rules can be defined at multiple levels of design
1686  * specification. When a routing or placement rule is defined for an object at
1687  * multiple levels, a predefined routing or placement precedence order
1688  * automatically determines which rule to apply to the object. The routing rule
1689  * precedence order is
1690  *
1691  * pcb < layer < class < class layer < group_set < group_set layer < net <
1692  * net layer < group < group layer < fromto < fromto layer < class_class <
1693  * class_class layer < padstack < region < class region < net region <
1694  * class_class region
1695  *
1696  * A pcb rule (global rule for the PCB design) has the lowest precedence in the
1697  * hierarchy. A class-to-class region rule has the highest precedence. Rules
1698  * set at one level of the hierarchy override conflicting rules set at lower
1699  * levels. The placement rule precedence order is
1700  *
1701  * pcb < image_set < image < component < super cluster < room <
1702  * room_image_set < family_family < image_image
1703  *
1704  * A pcb rule (global rule for the PCB design) has the lowest precedence in the
1705  * hierarchy. An image-to-image rule has the highest precedence. Rules set at
1706  * one level of the hierarchy override conflicting rules set at lower levels.
1707  */
1708 
1709  char text[256];
1710 
1711  CLASS* clazz = new CLASS( pcb->network );
1712 
1713  pcb->network->classes.push_back( clazz );
1714 
1715  // freerouter creates a class named 'default' anyway, and if we
1716  // try and use that, we end up with two 'default' via rules so use
1717  // something else as the name of our default class.
1718  clazz->class_id = TO_UTF8( aNetClass->GetName() );
1719 
1720  for( NETCLASS::iterator net = aNetClass->begin(); net != aNetClass->end(); ++net )
1721  clazz->net_ids.push_back( TO_UTF8( *net ) );
1722 
1723  clazz->rules = new RULE( clazz, T_rule );
1724 
1725  // output the track width.
1726  int trackWidth = aNetClass->GetTrackWidth();
1727  sprintf( text, "(width %.6g)", scale( trackWidth ) );
1728  clazz->rules->rules.push_back( text );
1729 
1730  // output the clearance.
1731  int clearance = aNetClass->GetClearance();
1732  sprintf( text, "(clearance %.6g)", scale( clearance ) + safetyMargin );
1733  clazz->rules->rules.push_back( text );
1734 
1735  if( aNetClass->GetName() == NETCLASS::Default )
1736  {
1737  clazz->class_id = "kicad_default";
1738  }
1739 
1740  // the easiest way to get the via name is to create a via (which generates
1741  // the name internal to the PADSTACK), and then grab the name and then
1742  // delete the via. There are not that many netclasses so
1743  // this should never become a performance issue.
1744 
1745  PADSTACK* via = makeVia( aNetClass->GetViaDiameter(), aNetClass->GetViaDrill(),
1747 
1748  snprintf( text, sizeof(text), "(use_via %s)", via->GetPadstackId().c_str() );
1749  clazz->circuit.push_back( text );
1750 
1751  delete via;
1752 }
1753 
1754 
1756 {
1757  for( MODULE* module = aBoard->m_Modules; module; module = module->Next() )
1758  {
1759  module->SetFlag( 0 );
1760  if( module->GetLayer() == B_Cu )
1761  {
1762  module->Flip( module->GetPosition() );
1763  module->SetFlag( 1 );
1764  }
1765  }
1766 
1767  modulesAreFlipped = true;
1768 }
1769 
1770 
1772 {
1773  if( !modulesAreFlipped )
1774  return;
1775 
1776  // DSN Images (=KiCad MODULES and pads) must be presented from the
1777  // top view. Restore those that were flipped.
1778  for( MODULE* module = aBoard->m_Modules; module; module = module->Next() )
1779  {
1780  if( module->GetFlag() )
1781  {
1782  module->Flip( module->GetPosition() );
1783  module->SetFlag( 0 );
1784  }
1785  }
1786 
1787  modulesAreFlipped = false;
1788 }
1789 
1790 } // namespace DSN
int GetFlag() const
Definition: class_module.h:229
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:106
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:199
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:106
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown...
Definition: common.h:167
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:524
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:121
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:486
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:256
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:602
std::pair< STRINGSET::iterator, bool > STRINGSET_PAIR
const std::string & GetPadstackId()
Definition: specctra.h:2139
const LIB_ID & GetFPID() const
Definition: class_module.h:191
#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:158
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:254
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:141
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:255
Class NETCLASSES is a container for NETCLASS instances.
Definition: netclass.h:231
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:188
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:90
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:533
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
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:227
CLASSLIST classes
Definition: specctra.h:2812
static PATH * makePath(const POINT &aStart, const POINT &aEnd, const std::string &aLayerName)
Function makePath creates a PATH element with a single straight line, a pair of vertices.
std::vector< int > kicadLayer2pcb
maps BOARD layer number to PCB layer numbers
Definition: specctra.h:3625
COMPONENT * LookupCOMPONENT(const std::string &imageName)
Function LookupCOMPONENT looks up a COMPONENT by name.
Definition: specctra.h:1817
void Collect(BOARD_ITEM *aBoard, const KICAD_T aScanList[])
Collect BOARD_ITEM objects using this class&#39;s Inspector method, which does the collection.
Definition: collectors.cpp:498
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:605
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
Struct POINT is a holder for a point in the SPECCTRA DSN coordinate system.
Definition: specctra.h:94
void FromBOARD(BOARD *aBoard)
Function FromBOARD adds the entire BOARD to the PCB but does not write it out.
const wxString & GetNetname() const
Function GetNetname.
Class WIRE corresponds to <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
const wxString SpecctraDsnFileExtension
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
void SetCorners(const POINT &aPoint0, const POINT &aPoint1)
Definition: specctra.h:460
bool GetDoNotAllowVias() const
Definition: class_zone.h:604
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:169
const wxString & GetReference() const
Function GetReference.
Definition: class_module.h:458
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: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:434
PLACEMENT * placement
Definition: specctra.h:3144
const char * c_str() const
Definition: utf8.h:107
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
static double mapY(int y)
RULE * rules
Definition: specctra.h:2732
Class ITERATOR_TEMPLATE.
NETCLASSPTR GetDefault() const
Function GetDefault.
Definition: netclass.h:275
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:263
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:235
wxPoint m_Start0
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:590
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:650
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:47
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
const wxPoint GetPosition() const override
Definition: class_module.h:182
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:199
const wxPoint & GetOffset() const
Definition: class_pad.h:278
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:773
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