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