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