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