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 #include <math/util.h> // for KiROUND
40 
41 #include <set> // std::set
42 #include <map> // std::map
43 
44 #include <class_board.h>
45 #include <class_module.h>
46 #include <class_edge_mod.h>
47 #include <class_track.h>
48 #include <class_zone.h>
49 #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  SHAPE_LINE_CHAIN& polygonal_shape = cornerBuffer.Outline( 0 );
493 
494  for( int ndx=0; ndx < reportedLayers; ++ndx )
495  {
496  SHAPE* shape = new SHAPE( padstack );
497 
498  padstack->Append( shape );
499 
500  // a T_polygon exists as a PATH
501  PATH* polygon = new PATH( shape, T_polygon );
502 
503  shape->SetShape( polygon );
504 
505  polygon->SetLayerId( layerName[ndx] );
506  // append a closed polygon
507  POINT first_corner;
508 
509  for( int idx = 0; idx < polygonal_shape.PointCount(); idx++ )
510  {
511  POINT corner( scale( polygonal_shape.CPoint( idx ).x ),
512  scale( -polygonal_shape.CPoint( idx ).y ) );
513  corner += dsnOffset;
514  polygon->AppendPoint( corner );
515 
516  if( idx == 0 )
517  first_corner = corner;
518  }
519  polygon->AppendPoint( first_corner ); // Close polygon
520  }
521 
522  // this string _must_ be unique for a given physical shape
523  snprintf( name, sizeof(name), "RoundRect%sPad_%.6gx%.6g_%.6g_um",
524  uniqifier.c_str(),
525  IU2um( aPad->GetSize().x ),
526  IU2um( aPad->GetSize().y ), IU2um( rradius ) );
527 
528  name[ sizeof(name) - 1 ] = 0;
529 
530  padstack->SetPadstackId( name );
531  }
532  break;
533 
534  case PAD_SHAPE_CUSTOM:
535  {
536  std::vector<wxPoint> polygonal_shape;
537  const SHAPE_POLY_SET& pad_shape = aPad->GetCustomShapeAsPolygon();
538 
539  #ifdef EXPORT_CUSTOM_PADS_CONVEX_HULL
540  BuildConvexHull( polygonal_shape, pad_shape );
541  #else
542  const SHAPE_LINE_CHAIN& p_outline = pad_shape.COutline( 0 );
543  for( int ii = 0; ii < p_outline.PointCount(); ++ii )
544  polygonal_shape.push_back( wxPoint( p_outline.CPoint( ii ) ) );
545  #endif
546 
547  // The polygon must be closed
548  if( polygonal_shape.front() != polygonal_shape.back() )
549  polygonal_shape.push_back( polygonal_shape.front() );
550 
551  for( int ndx=0; ndx < reportedLayers; ++ndx )
552  {
553  SHAPE* shape = new SHAPE( padstack );
554 
555  padstack->Append( shape );
556 
557  // a T_polygon exists as a PATH
558  PATH* polygon = new PATH( shape, T_polygon );
559 
560  shape->SetShape( polygon );
561 
562  polygon->SetLayerId( layerName[ndx] );
563 
564  for( unsigned idx = 0; idx < polygonal_shape.size(); idx++ )
565  {
566  POINT corner( scale( polygonal_shape[idx].x ), scale( -polygonal_shape[idx].y ) );
567  corner += dsnOffset;
568  polygon->AppendPoint( corner );
569  }
570  }
571 
572  // this string _must_ be unique for a given physical shape, so try to make it unique
573  EDA_RECT rect = aPad->GetBoundingBox();
574  snprintf( name, sizeof(name), "Cust%sPad_%.6gx%.6g_%.6gx_%.6g_%d_um",
575  uniqifier.c_str(), IU2um( aPad->GetSize().x ), IU2um( aPad->GetSize().y ),
576  IU2um( rect.GetWidth() ), IU2um( rect.GetHeight() ),
577  (int)polygonal_shape.size() );
578  name[ sizeof(name)-1 ] = 0;
579 
580  padstack->SetPadstackId( name );
581  }
582  break;
583  }
584 
585  return padstack;
586 }
587 
588 
590 typedef std::map<wxString, int> PINMAP;
591 
592 
594 {
595  PINMAP pinmap;
596  wxString padName;
597 
598  PCB_TYPE_COLLECTOR moduleItems;
599 
600  // get all the MODULE's pads.
601  moduleItems.Collect( aModule, scanPADs );
602 
603  IMAGE* image = new IMAGE(0);
604 
605  image->image_id = aModule->GetFPID().Format().c_str();
606 
607  // from the pads, and make an IMAGE using collated padstacks.
608  for( int p=0; p < moduleItems.GetCount(); ++p )
609  {
610  D_PAD* pad = (D_PAD*) moduleItems[p];
611 
612  // see if this pad is a through hole with no copper on its perimeter
613  if( isRoundKeepout( pad ) )
614  {
615  double diameter = scale( pad->GetDrillSize().x );
616  POINT vertex = mapPt( pad->GetPos0() );
617 
618  int layerCount = aBoard->GetCopperLayerCount();
619 
620  for( int layer=0; layer<layerCount; ++layer )
621  {
622  KEEPOUT* keepout = new KEEPOUT( image, T_keepout );
623 
624  image->keepouts.push_back( keepout );
625 
626  CIRCLE* circle = new CIRCLE( keepout );
627 
628  keepout->SetShape( circle );
629 
630  circle->SetDiameter( diameter );
631  circle->SetVertex( vertex );
632  circle->SetLayerId( layerIds[layer].c_str() );
633  }
634  }
635  // else if() could there be a square keepout here?
636 
637  else
638  {
639  // Pads not on copper layers (i.e. only on tech layers) are ignored
640  // because they create invalid pads in .dsn file for freeroute
641  LSET mask_copper_layers = pad->GetLayerSet() & LSET::AllCuMask();
642 
643  if( !mask_copper_layers.any() )
644  continue;
645 
646  PADSTACK* padstack = makePADSTACK( aBoard, pad );
647  PADSTACKSET::iterator iter = padstackset.find( *padstack );
648 
649  if( iter != padstackset.end() )
650  {
651  // padstack is a duplicate, delete it and use the original
652  delete padstack;
653  padstack = (PADSTACK*) *iter.base(); // folklore, be careful here
654  }
655  else
656  {
657  padstackset.insert( padstack );
658  }
659 
660  PIN* pin = new PIN( image );
661 
662  padName = pad->GetName();
663  pin->pin_id = TO_UTF8( padName );
664 
665  if( padName!=wxEmptyString && pinmap.find( padName )==pinmap.end() )
666  {
667  pinmap[ padName ] = 0;
668  }
669  else // pad name is a duplicate within this module
670  {
671  char buf[32];
672 
673  int duplicates = ++pinmap[ padName ];
674 
675  sprintf( buf, "@%d", duplicates );
676 
677  pin->pin_id += buf; // append "@1" or "@2", etc. to pin name
678  }
679 
680  pin->kiNetCode = pad->GetNetCode();
681 
682  image->pins.push_back( pin );
683 
684  pin->padstack_id = padstack->padstack_id;
685 
686  double angle = pad->GetOrientationDegrees() - aModule->GetOrientationDegrees();
688  pin->SetRotation( angle );
689 
690  wxPoint pos( pad->GetPos0() );
691 
692  pin->SetVertex( mapPt( pos ) );
693  }
694  }
695 
696 #if 1 // enable image (outline) scopes.
697  static const KICAD_T scanEDGEs[] = { PCB_MODULE_EDGE_T, EOT };
698 
699  // get all the MODULE's EDGE_MODULEs and convert those to DSN outlines.
700  moduleItems.Collect( aModule, scanEDGEs );
701 
702  for( int i = 0; i<moduleItems.GetCount(); ++i )
703  {
704  EDGE_MODULE* graphic = (EDGE_MODULE*) moduleItems[i];
705  SHAPE* outline;
706  PATH* path;
707 
708  switch( graphic->GetShape() )
709  {
710  case S_SEGMENT:
711  outline = new SHAPE( image, T_outline );
712 
713  image->Append( outline );
714  path = new PATH( outline );
715 
716  outline->SetShape( path );
717  path->SetAperture( scale( graphic->GetWidth() ) );
718  path->SetLayerId( "signal" );
719  path->AppendPoint( mapPt( graphic->GetStart0() ) );
720  path->AppendPoint( mapPt( graphic->GetEnd0() ) );
721  break;
722 
723  case S_CIRCLE:
724  {
725  // this is best done by 4 QARC's but freerouter does not yet support QARCs.
726  // for now, support by using line segments.
727 
728  outline = new SHAPE( image, T_outline );
729 
730  image->Append( outline );
731  path = new PATH( outline );
732 
733  outline->SetShape( path );
734  path->SetAperture( scale( graphic->GetWidth() ) );
735  path->SetLayerId( "signal" );
736 
737  // Do the math using KiCad units, that way we stay out of the
738  // scientific notation range of floating point numbers in the
739  // DSN file. We do not parse scientific notation in our own
740  // lexer/beautifier, and the spec is not clear that this is
741  // required. Fixed point floats are all that should be needed.
742 
743  double radius = GetLineLength( graphic->GetStart(), graphic->GetEnd() );
744 
745  // seg count to approximate circle by line segments
746  int seg_per_circle = GetArcToSegmentCount( radius, ARC_LOW_DEF, 360.0 );
747 
748  for( int ii = 0; ii < seg_per_circle; ++ii )
749  {
750  double radians = 2*M_PI / seg_per_circle * ii;
751  wxPoint point( KiROUND( radius * cos( radians ) ),
752  KiROUND( radius * sin( radians ) ) );
753 
754  point += graphic->m_Start0; // an offset
755 
756  path->AppendPoint( mapPt( point ) );
757  }
758  // The shape must be closed
759  wxPoint point( radius , 0 );
760  point += graphic->m_Start0;
761  path->AppendPoint( mapPt( point ) );
762  }
763  break;
764 
765  case S_RECT:
766  case S_ARC:
767  default:
768  DBG( printf( "makeIMAGE(): unsupported shape %s\n",
769  TO_UTF8( BOARD_ITEM::ShowShape( graphic->GetShape() ) ) ); )
770  continue;
771  }
772  }
773 
774 #endif
775 
776  return image;
777 }
778 
779 
780 PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter, int aDrillDiameter,
781  int aTopLayer, int aBotLayer )
782 {
783  char name[48];
784  PADSTACK* padstack = new PADSTACK();
785  double dsnDiameter = scale( aCopperDiameter );
786 
787  for( int layer=aTopLayer; layer<=aBotLayer; ++layer )
788  {
789  SHAPE* shape = new SHAPE( padstack );
790 
791  padstack->Append( shape );
792 
793  CIRCLE* circle = new CIRCLE( shape );
794 
795  shape->SetShape( circle );
796 
797  circle->SetDiameter( dsnDiameter );
798  circle->SetLayerId( layerIds[layer].c_str() );
799  }
800 
801  snprintf( name, sizeof(name), "Via[%d-%d]_%.6g:%.6g_um",
802  aTopLayer, aBotLayer, dsnDiameter,
803  // encode the drill value into the name for later import
804  IU2um( aDrillDiameter )
805  );
806 
807  name[ sizeof(name) - 1 ] = 0;
808  padstack->SetPadstackId( name );
809 
810  return padstack;
811 }
812 
813 
815 {
816  PCB_LAYER_ID topLayerNum;
817  PCB_LAYER_ID botLayerNum;
818 
819  aVia->LayerPair( &topLayerNum, &botLayerNum );
820 
821  int topLayer = kicadLayer2pcb[topLayerNum];
822  int botLayer = kicadLayer2pcb[botLayerNum];
823 
824  if( topLayer > botLayer )
825  std::swap( topLayer, botLayer );
826 
827  return makeVia( aVia->GetWidth(), aVia->GetDrillValue(), topLayer, botLayer );
828 }
829 
830 
831 void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary )
832 {
833  wxString errMessage;
834  SHAPE_POLY_SET outlines;
835 
836  aBoard->GetBoardPolygonOutlines( outlines, &errMessage );
837 
838  for( int cnt = 0; cnt < outlines.OutlineCount(); cnt++ ) // Should be one outline
839  {
840  PATH* path = new PATH( boundary );
841  boundary->paths.push_back( path );
842  path->layer_id = "pcb";
843 
844  SHAPE_LINE_CHAIN& outline = outlines.Outline( cnt );
845 
846  for( int ii = 0; ii < outline.PointCount(); ii++ )
847  {
848  wxPoint pos( outline.CPoint( ii ).x, outline.CPoint( ii ).y );
849  path->AppendPoint( mapPt( pos ) );
850  }
851 
852  // Close polygon:
853  wxPoint pos0( outline.CPoint( 0 ).x, outline.CPoint( 0 ).y );
854  path->AppendPoint( mapPt( pos0 ) );
855 
856  // Generate holes as keepout:
857  for( int ii = 0; ii < outlines.HoleCount( cnt ); ii++ )
858  {
859  // emit a signal layers keepout for every interior polygon left...
860  KEEPOUT* keepout = new KEEPOUT( NULL, T_keepout );
861  PATH* poly_ko = new PATH( NULL, T_polygon );
862 
863  keepout->SetShape( poly_ko );
864  poly_ko->SetLayerId( "signal" );
865  pcb->structure->keepouts.push_back( keepout );
866 
867  SHAPE_LINE_CHAIN& hole = outlines.Hole( cnt, ii );
868 
869  for( int jj = 0; jj < hole.PointCount(); jj++ )
870  {
871  wxPoint pos( hole.CPoint( jj ).x, hole.CPoint( jj ).y );
872  poly_ko->AppendPoint( mapPt( pos ) );
873  }
874 
875  // Close polygon:
876  wxPoint pos( hole.CPoint( 0 ).x, hole.CPoint( 0 ).y );
877  poly_ko->AppendPoint( mapPt( pos ) );
878  }
879  }
880 
881  if( !errMessage.IsEmpty() )
882  wxLogMessage( errMessage );
883 }
884 
885 
886 typedef std::set<std::string> STRINGSET;
887 typedef std::pair<STRINGSET::iterator, bool> STRINGSET_PAIR;
888 
889 
891 {
892  PCB_TYPE_COLLECTOR items;
893 
894  static const KICAD_T scanMODULEs[] = { PCB_MODULE_T, EOT };
895 
896  // Not all boards are exportable. Check that all reference Ids are unique.
897  // Unless they are unique, we cannot import the session file which comes
898  // back to us later from the router.
899  {
900  items.Collect( aBoard, scanMODULEs );
901 
902  STRINGSET refs; // holds module reference designators
903 
904  for( int i=0; i<items.GetCount(); ++i )
905  {
906  MODULE* module = (MODULE*) items[i];
907 
908  if( module->GetReference() == wxEmptyString )
909  {
910  THROW_IO_ERROR( wxString::Format( _( "Symbol with value of \"%s\" has empty reference id." ),
911  GetChars( module->GetValue() ) ) );
912  }
913 
914  // if we cannot insert OK, that means the reference has been seen before.
915  STRINGSET_PAIR refpair = refs.insert( TO_UTF8( module->GetReference() ) );
916  if( !refpair.second ) // insert failed
917  {
918  THROW_IO_ERROR( wxString::Format( _( "Multiple symbols have identical reference IDs of \"%s\"." ),
919  GetChars( module->GetReference() ) ) );
920  }
921  }
922  }
923 
924  if( !pcb )
926 
927  //-----<layer_descriptor>-----------------------------------------------
928  {
929  // specctra wants top physical layer first, then going down to the
930  // bottom most physical layer in physical sequence.
931  // @question : why does KiCad not display layers in that order?
932 
933  buildLayerMaps( aBoard );
934 
935  int layerCount = aBoard->GetCopperLayerCount();
936 
937  for( int pcbNdx=0; pcbNdx<layerCount; ++pcbNdx )
938  {
939  LAYER* layer = new LAYER( pcb->structure );
940 
941  pcb->structure->layers.push_back( layer );
942 
943  layer->name = layerIds[pcbNdx];
944 
945  DSN_T layerType;
946 
947  switch( aBoard->GetLayerType( pcbLayer2kicad[pcbNdx] ) )
948  {
949  default:
950  case LT_SIGNAL: layerType = T_signal; break;
951  case LT_POWER: layerType = T_power; break;
952 
953 #if 1 // Freerouter does not support type "mixed", only signal and power.
954  // Remap "mixed" to "signal".
955  case LT_MIXED: layerType = T_signal; break;
956 #else
957  case LT_MIXED: layerType = T_mixed; break;
958 #endif
959  case LT_JUMPER: layerType = T_jumper; break;
960  }
961 
962  layer->layer_type = layerType;
963 
964  layer->properties.push_back( PROPERTY() );
965  PROPERTY* property = &layer->properties.back();
966  property->name = "index";
967  char temp[32];
968  sprintf( temp, "%d", pcbNdx );
969  property->value = temp;
970  }
971  }
972 
973  // a space in a quoted token is NOT a terminator, true establishes this.
975 
976  //-----<unit_descriptor> & <resolution_descriptor>--------------------
977  {
978  // tell freerouter to use "tenths of micrometers",
979  // which is 100 nm resolution. Possibly more resolution is possible
980  // in freerouter, but it would need testing.
981 
982  pcb->unit->units = T_um;
983  pcb->resolution->units = T_um;
984  pcb->resolution->value = 10; // tenths of a um
985  // pcb->resolution->value = 1000; // "thousandths of a um" (i.e. "nm")
986  }
987 
988  //-----<boundary_descriptor>------------------------------------------
989  {
990  // Because fillBOUNDARY() can throw an exception, we link in an
991  // empty boundary so the BOUNDARY does not get lost in the event of
992  // of an exception.
993  BOUNDARY* boundary = new BOUNDARY( 0 );
994 
995  pcb->structure->SetBOUNDARY( boundary );
996  fillBOUNDARY( aBoard, boundary );
997  }
998 
999 
1000  //-----<rules>--------------------------------------------------------
1001  {
1002  char rule[80];
1003  NETCLASSPTR defaultClass = aBoard->GetDesignSettings().GetDefault();
1004 
1005  int defaultTrackWidth = defaultClass->GetTrackWidth();
1006  int defaultClearance = defaultClass->GetClearance();
1007 
1008  double clearance = scale( defaultClearance );
1009 
1010  STRINGS& rules = pcb->structure->rules->rules;
1011 
1012  sprintf( rule, "(width %.6g)", scale( defaultTrackWidth ) );
1013  rules.push_back( rule );
1014 
1015  sprintf( rule, "(clearance %.6g)", clearance + safetyMargin );
1016  rules.push_back( rule );
1017 
1018  // On a high density board (a board with 4 mil tracks, 4 mil spacing)
1019  // a typical solder mask clearance will be 2-3 mils.
1020  // This exposes 2 to 3 mils of bare board around each pad, and would
1021  // leave only 1 to 2 mils of solder mask between the solder mask's boundary
1022  // to the edge of any trace within "clearance" of the pad. So we need at least
1023  // 2 mils *extra* clearance for traces which would come near a pad on
1024  // a different net. So if the baseline trace to trace clearance was say 4 mils, then
1025  // the SMD to trace clearance should be at least 6 mils.
1026  double default_smd = clearance + safetyMargin;
1027 
1028  if( default_smd <= 6.0 )
1029  default_smd = 6.0;
1030 
1031  sprintf( rule, "(clearance %.6g (type default_smd))", default_smd );
1032 
1033  rules.push_back( rule );
1034 
1035  /* see: http://www.freerouting.net/usren/viewtopic.php?f=5&t=339#p474
1036  sprintf( rule, "(clearance %.6g (type pad_to_turn_gap))", clearance + safetyMargin );
1037  rules.push_back( rule );
1038 
1039  sprintf( rule, "(clearance %.6g (type smd_to_turn_gap))", clearance + safetyMargin );
1040  rules.push_back( rule );
1041 
1042  sprintf( rule, "(clearance %.6g (type via_via))", clearance + safetyMargin );
1043  rules.push_back( rule );
1044 
1045  sprintf( rule, "(clearance %.6g (type via_smd))", clearance + safetyMargin );
1046  rules.push_back( rule );
1047 
1048  sprintf( rule, "(clearance %.6g (type via_pin))", clearance + safetyMargin );
1049  rules.push_back( rule );
1050 
1051  sprintf( rule, "(clearance %.6g (type pin_pin))", clearance + safetyMargin );
1052  rules.push_back( rule );
1053 
1054  sprintf( rule, "(clearance %.6g (type smd_pin))", clearance + safetyMargin );
1055  rules.push_back( rule );
1056  */
1057 
1058  // Pad to pad spacing on a single SMT part can be closer than our
1059  // clearance, we don't want freerouter complaining about that, so
1060  // output a significantly smaller pad to pad clearance to freerouter.
1061  clearance = scale( defaultClearance ) / 4;
1062 
1063  sprintf( rule, "(clearance %.6g (type smd_smd))", clearance );
1064  rules.push_back( rule );
1065  }
1066 
1067 
1068  //-----<zone containers (not keepout areas) become planes>--------------------------------
1069  // Note: only zones are output here, keepout areas be be created later
1070  {
1071  int netlessZones = 0;
1072 
1073  static const KICAD_T scanZONEs[] = { PCB_ZONE_AREA_T, EOT };
1074  items.Collect( aBoard, scanZONEs );
1075 
1076  for( int i = 0; i<items.GetCount(); ++i )
1077  {
1078  ZONE_CONTAINER* item = (ZONE_CONTAINER*) items[i];
1079 
1080  if( item->GetIsKeepout() )
1081  continue;
1082 
1083  // Currently, we export only copper layers
1084  if( ! IsCopperLayer( item->GetLayer() ) )
1085  continue;
1086 
1087  COPPER_PLANE* plane = new COPPER_PLANE( pcb->structure );
1088 
1089  pcb->structure->planes.push_back( plane );
1090 
1091  PATH* mainPolygon = new PATH( plane, T_polygon );
1092 
1093  plane->SetShape( mainPolygon );
1094 
1095  plane->name = TO_UTF8( item->GetNetname() );
1096 
1097  if( plane->name.size() == 0 )
1098  {
1099  char name[32];
1100 
1101  // This is one of those no connection zones, netcode=0, and it has no name.
1102  // Create a unique, bogus netname.
1103  NET* no_net = new NET( pcb->network );
1104 
1105  sprintf( name, "@:no_net_%d", netlessZones++ );
1106  no_net->net_id = name;
1107 
1108  // add the bogus net name to network->nets.
1109  pcb->network->nets.push_back( no_net );
1110 
1111  // use the bogus net name in the netless zone.
1112  plane->name = no_net->net_id;
1113  }
1114 
1115  mainPolygon->layer_id = layerIds[ kicadLayer2pcb[ item->GetLayer() ] ];
1116 
1117  // Handle the main outlines
1118  SHAPE_POLY_SET::ITERATOR iterator;
1119  wxPoint startpoint;
1120  bool is_first_point = true;
1121 
1122  for( iterator = item->IterateWithHoles(); iterator; iterator++ )
1123  {
1124  wxPoint point( iterator->x, iterator->y );
1125 
1126  if( is_first_point )
1127  {
1128  startpoint = point;
1129  is_first_point = false;
1130  }
1131 
1132  mainPolygon->AppendPoint( mapPt( point ) );
1133 
1134  // this was the end of the main polygon
1135  if( iterator.IsEndContour() )
1136  {
1137  // Close polygon
1138  mainPolygon->AppendPoint( mapPt( startpoint ) );
1139  break;
1140  }
1141  }
1142 
1143  WINDOW* window = 0;
1144  PATH* cutout = 0;
1145 
1146  bool isStartContour = true;
1147 
1148  // handle the cutouts
1149  for( iterator++; iterator; iterator++ )
1150  {
1151  if( isStartContour )
1152  {
1153  is_first_point = true;
1154  window = new WINDOW( plane );
1155 
1156  plane->AddWindow( window );
1157 
1158  cutout = new PATH( window, T_polygon );
1159 
1160  window->SetShape( cutout );
1161 
1162  cutout->layer_id = layerIds[ kicadLayer2pcb[ item->GetLayer() ] ];
1163  }
1164 
1165  // If the point in this iteration is the last of the contour, the next iteration
1166  // will start with a new contour.
1167  isStartContour = iterator.IsEndContour();
1168 
1169  wxASSERT( window );
1170  wxASSERT( cutout );
1171 
1172  wxPoint point(iterator->x, iterator->y );
1173 
1174  if( is_first_point )
1175  {
1176  startpoint = point;
1177  is_first_point = false;
1178  }
1179 
1180  cutout->AppendPoint( mapPt(point) );
1181 
1182  // Close the polygon
1183  if( iterator.IsEndContour() )
1184  cutout->AppendPoint( mapPt( startpoint ) );
1185  }
1186  }
1187  }
1188 
1189  //-----<zone containers flagged keepout areas become keepout>--------------------------------
1190  {
1191  static const KICAD_T scanZONEs[] = { PCB_ZONE_AREA_T, EOT };
1192  items.Collect( aBoard, scanZONEs );
1193 
1194  for( int i=0; i<items.GetCount(); ++i )
1195  {
1196  ZONE_CONTAINER* item = (ZONE_CONTAINER*) items[i];
1197 
1198  if( ! item->GetIsKeepout() )
1199  continue;
1200 
1201  // keepout areas have a type. types are
1202  // T_place_keepout, T_via_keepout, T_wire_keepout,
1203  // T_bend_keepout, T_elongate_keepout, T_keepout.
1204  // Pcbnew knows only T_keepout, T_via_keepout and T_wire_keepout
1205  DSN_T keepout_type;
1206 
1207  if( item->GetDoNotAllowVias() && item->GetDoNotAllowTracks() )
1208  keepout_type = T_keepout;
1209  else if( item->GetDoNotAllowVias() )
1210  keepout_type = T_via_keepout;
1211  else if( item->GetDoNotAllowTracks() )
1212  keepout_type = T_wire_keepout;
1213  else
1214  keepout_type = T_keepout;
1215 
1216  // Now, build keepout polygon on each copper layer where the item
1217  // keepout is living (keepout zones can live on many copper layers)
1218  const int copperCount = aBoard->GetCopperLayerCount();
1219 
1220  for( int layer = 0; layer < copperCount; layer++ )
1221  {
1222  if( layer == copperCount-1)
1223  layer = B_Cu;
1224 
1225  if( !item->IsOnLayer( PCB_LAYER_ID( layer ) ) )
1226  continue;
1227 
1228  KEEPOUT* keepout = new KEEPOUT( pcb->structure, keepout_type );
1229  pcb->structure->keepouts.push_back( keepout );
1230 
1231  PATH* mainPolygon = new PATH( keepout, T_polygon );
1232  keepout->SetShape( mainPolygon );
1233 
1234  mainPolygon->layer_id = layerIds[ kicadLayer2pcb[ layer ] ];
1235 
1236  // Handle the main outlines
1237  SHAPE_POLY_SET::ITERATOR iterator;
1238  bool is_first_point = true;
1239  wxPoint startpoint;
1240 
1241  for( iterator = item->IterateWithHoles(); iterator; iterator++ )
1242  {
1243  wxPoint point( iterator->x, iterator->y );
1244 
1245  if( is_first_point )
1246  {
1247  startpoint = point;
1248  is_first_point = false;
1249  }
1250 
1251  mainPolygon->AppendPoint( mapPt(point) );
1252 
1253  // this was the end of the main polygon
1254  if( iterator.IsEndContour() )
1255  {
1256  mainPolygon->AppendPoint( mapPt( startpoint ) );
1257  break;
1258  }
1259  }
1260 
1261  WINDOW* window = nullptr;
1262  PATH* cutout = nullptr;
1263 
1264  bool isStartContour = true;
1265 
1266  // handle the cutouts
1267  for( iterator++; iterator; iterator++ )
1268  {
1269  if( isStartContour )
1270  {
1271  is_first_point = true;
1272  window = new WINDOW( keepout );
1273  keepout->AddWindow( window );
1274 
1275  cutout = new PATH( window, T_polygon );
1276 
1277  window->SetShape( cutout );
1278 
1279  cutout->layer_id = layerIds[ kicadLayer2pcb[ item->GetLayer() ] ];
1280  }
1281 
1282  isStartContour = iterator.IsEndContour();
1283 
1284  wxASSERT( window );
1285  wxASSERT( cutout );
1286 
1287  wxPoint point(iterator->x, iterator->y );
1288 
1289  if( is_first_point )
1290  {
1291  startpoint = point;
1292  is_first_point = false;
1293  }
1294 
1295  cutout->AppendPoint( mapPt(point) );
1296 
1297  // Close the polygon
1298  if( iterator.IsEndContour() )
1299  cutout->AppendPoint( mapPt( startpoint ) );
1300  }
1301  }
1302  }
1303  }
1304 
1305  //-----<build the images, components, and netlist>-----------------------
1306  {
1307  PIN_REF empty( pcb->network );
1308 
1309  std::string componentId;
1310 
1311  // find the highest numbered netCode within the board.
1312  int highestNetCode = aBoard->GetNetCount() - 1;
1313 
1314  deleteNETs();
1315 
1316  // expand the net vector to highestNetCode+1, setting empty to NULL
1317  nets.resize( highestNetCode + 1, NULL );
1318 
1319  for( unsigned i = 1 /* skip "No Net" at [0] */; i < nets.size(); ++i )
1320  nets[i] = new NET( pcb->network );
1321 
1322  for( unsigned ii = 0; ii < aBoard->GetNetCount(); ii++ )
1323  {
1324  NETINFO_ITEM* net = aBoard->FindNet( ii );
1325  int netcode = net->GetNet();
1326 
1327  if( netcode > 0 )
1328  nets[ netcode ]->net_id = TO_UTF8( net->GetNetname() );
1329  }
1330 
1331  items.Collect( aBoard, scanMODULEs );
1332 
1333  padstackset.clear();
1334 
1335  for( int m = 0; m<items.GetCount(); ++m )
1336  {
1337  MODULE* module = (MODULE*) items[m];
1338 
1339  IMAGE* image = makeIMAGE( aBoard, module );
1340 
1341  componentId = TO_UTF8( module->GetReference() );
1342 
1343  // create a net list entry for all the actual pins in the image
1344  // for the current module. location of this code is critical
1345  // because we fabricated some pin names to ensure unique-ness
1346  // of pin names within a module, do not move this code because
1347  // the life of this 'IMAGE* image' is not necessarily long. The
1348  // exported netlist will have some fabricated pin names in it.
1349  // If you don't like fabricated pin names, then make sure all pads
1350  // within your MODULEs are uniquely named!
1351  for( unsigned p = 0; p<image->pins.size(); ++p )
1352  {
1353  PIN* pin = &image->pins[p];
1354 
1355  int netcode = pin->kiNetCode;
1356 
1357  if( netcode > 0 )
1358  {
1359  NET* net = nets[netcode];
1360 
1361  net->pins.push_back( empty );
1362 
1363  PIN_REF& pin_ref = net->pins.back();
1364 
1365  pin_ref.component_id = componentId;
1366  pin_ref.pin_id = pin->pin_id;
1367  }
1368  }
1369 
1370 
1371  IMAGE* registered = pcb->library->LookupIMAGE( image );
1372 
1373  if( registered != image )
1374  {
1375  // If our new 'image' is not a unique IMAGE, delete it.
1376  // and use the registered one, known as 'image' after this.
1377  delete image;
1378  image = registered;
1379  }
1380 
1381  COMPONENT* comp = pcb->placement->LookupCOMPONENT( image->GetImageId() );
1382 
1383  PLACE* place = new PLACE( comp );
1384 
1385  comp->places.push_back( place );
1386 
1387  place->SetRotation( module->GetOrientationDegrees() );
1388  place->SetVertex( mapPt( module->GetPosition() ) );
1389  place->component_id = componentId;
1390  place->part_number = TO_UTF8( module->GetValue() );
1391 
1392  // module is flipped from bottom side, set side to T_back
1393  if( module->GetFlag() )
1394  {
1395  double angle = 180.0 - module->GetOrientationDegrees();
1397  place->SetRotation( angle );
1398 
1399  place->side = T_back;
1400  }
1401  }
1402 
1403  // copy the SPECCTRA_DB::padstackset to the LIBRARY. Since we are
1404  // removing, do not increment the iterator
1405  for( PADSTACKSET::iterator i = padstackset.begin(); i!=padstackset.end();
1406  i = padstackset.begin() )
1407  {
1408  PADSTACKSET::auto_type ps = padstackset.release( i );
1409  PADSTACK* padstack = ps.release();
1410 
1411  pcb->library->AddPadstack( padstack );
1412  }
1413 
1414  // copy our SPECCTRA_DB::nets to the pcb->network
1415  for( unsigned n = 1; n<nets.size(); ++n )
1416  {
1417  NET* net = nets[n];
1418 
1419  if( net->pins.size() )
1420  {
1421  // give ownership to pcb->network
1422  pcb->network->nets.push_back( net );
1423  nets[n] = 0;
1424  }
1425  }
1426  }
1427 
1428 
1429  //-----< output vias used in netclasses >-----------------------------------
1430  {
1431  NETCLASSES& nclasses = aBoard->GetDesignSettings().m_NetClasses;
1432 
1433  // Assume the netclass vias are all the same kind of thru, blind, or buried vias.
1434  // This is in lieu of either having each netclass via have its own layer pair in
1435  // the netclass dialog, or such control in the specctra export dialog.
1436 
1437 
1438  // if( aBoard->GetDesignSettings().m_CurrentViaType == VIA_THROUGH )
1439  {
1440  m_top_via_layer = 0; // first specctra cu layer is number zero.
1441  m_bot_via_layer = aBoard->GetCopperLayerCount()-1;
1442  }
1443  /*
1444  else
1445  {
1446  // again, should be in the BOARD:
1447  topLayer = kicadLayer2pcb[ GetScreen()->m_Route_Layer_TOP ];
1448  botLayer = kicadLayer2pcb[ GetScreen()->m_Route_Layer_BOTTOM ];
1449  }
1450  */
1451 
1452  // Add the via from the Default netclass first. The via container
1453  // in pcb->library preserves the sequence of addition.
1454 
1455  NETCLASSPTR netclass = nclasses.GetDefault();
1456 
1457  PADSTACK* via = makeVia( netclass->GetViaDiameter(), netclass->GetViaDrill(),
1459 
1460  // we AppendVia() this first one, there is no way it can be a duplicate,
1461  // the pcb->library via container is empty at this point. After this,
1462  // we'll have to use LookupVia().
1463  wxASSERT( pcb->library->vias.size() == 0 );
1464  pcb->library->AppendVia( via );
1465 
1466 #if 0
1467  // I've seen no way to make stock vias useable by freerouter. Also the
1468  // zero based diameter was leading to duplicates in the LookupVia() function.
1469  // User should use netclass based vias when going to freerouter.
1470 
1471  // Output the stock vias, but preserve uniqueness in the via container by
1472  // using LookupVia().
1473  for( unsigned i = 0; i < aBoard->m_ViasDimensionsList.size(); ++i )
1474  {
1475  int viaSize = aBoard->m_ViasDimensionsList[i].m_Diameter;
1476  int viaDrill = aBoard->m_ViasDimensionsList[i].m_Drill;
1477 
1478  via = makeVia( viaSize, viaDrill,
1480 
1481  // maybe add 'via' to the library, but only if unique.
1482  PADSTACK* registered = pcb->library->LookupVia( via );
1483 
1484  if( registered != via )
1485  delete via;
1486  }
1487 #endif
1488 
1489  // set the "spare via" index at the start of the
1490  // pcb->library->spareViaIndex = pcb->library->vias.size();
1491 
1492  // output the non-Default netclass vias
1493  for( NETCLASSES::iterator nc = nclasses.begin(); nc != nclasses.end(); ++nc )
1494  {
1495  netclass = nc->second;
1496 
1497  via = makeVia( netclass->GetViaDiameter(), netclass->GetViaDrill(),
1499 
1500  // maybe add 'via' to the library, but only if unique.
1501  PADSTACK* registered = pcb->library->LookupVia( via );
1502 
1503  if( registered != via )
1504  delete via;
1505  }
1506  }
1507 
1508 
1509 #if 1 // do existing wires and vias
1510 
1511  //-----<create the wires from tracks>-----------------------------------
1512  {
1513  // export all of them for now, later we'll decide what controls we need
1514  // on this.
1515  static const KICAD_T scanTRACKs[] = { PCB_TRACE_T, EOT };
1516 
1517  items.Collect( aBoard, scanTRACKs );
1518 
1519  std::string netname;
1520  WIRING* wiring = pcb->wiring;
1521  PATH* path = 0;
1522 
1523  int old_netcode = -1;
1524  int old_width = -1;
1525  LAYER_NUM old_layer = UNDEFINED_LAYER;
1526 
1527  for( int i=0; i<items.GetCount(); ++i )
1528  {
1529  TRACK* track = (TRACK*) items[i];
1530 
1531  int netcode = track->GetNetCode();
1532 
1533  if( netcode == 0 )
1534  continue;
1535 
1536  if( old_netcode != netcode ||
1537  old_width != track->GetWidth() ||
1538  old_layer != track->GetLayer() ||
1539  (path && path->points.back() != mapPt(track->GetStart()) )
1540  )
1541  {
1542  old_width = track->GetWidth();
1543  old_layer = track->GetLayer();
1544 
1545  if( old_netcode != netcode )
1546  {
1547  old_netcode = netcode;
1548  NETINFO_ITEM* net = aBoard->FindNet( netcode );
1549  wxASSERT( net );
1550  netname = TO_UTF8( net->GetNetname() );
1551  }
1552 
1553  WIRE* wire = new WIRE( wiring );
1554 
1555  wiring->wires.push_back( wire );
1556  wire->net_id = netname;
1557 
1558  wire->wire_type = T_protect; // @todo, this should be configurable
1559 
1560  LAYER_NUM kiLayer = track->GetLayer();
1561  int pcbLayer = kicadLayer2pcb[kiLayer];
1562 
1563  path = new PATH( wire );
1564 
1565  wire->SetShape( path );
1566 
1567  path->layer_id = layerIds[pcbLayer];
1568  path->aperture_width = scale( old_width );
1569 
1570  path->AppendPoint( mapPt( track->GetStart() ) );
1571  }
1572 
1573  if( path ) // Should not occur
1574  path->AppendPoint( mapPt( track->GetEnd() ) );
1575  }
1576  }
1577 
1578 
1579  //-----<export the existing real BOARD instantiated vias>-----------------
1580  {
1581  // Export all vias, once per unique size and drill diameter combo.
1582  static const KICAD_T scanVIAs[] = { PCB_VIA_T, EOT };
1583 
1584  items.Collect( aBoard, scanVIAs );
1585 
1586  for( int i = 0; i<items.GetCount(); ++i )
1587  {
1588  ::VIA* via = (::VIA*) items[i];
1589  wxASSERT( via->Type() == PCB_VIA_T );
1590 
1591  int netcode = via->GetNetCode();
1592 
1593  if( netcode == 0 )
1594  continue;
1595 
1596  PADSTACK* padstack = makeVia( via );
1597  PADSTACK* registered = pcb->library->LookupVia( padstack );
1598 
1599  // if the one looked up is not our padstack, then delete our padstack
1600  // since it was a duplicate of one already registered.
1601  if( padstack != registered )
1602  {
1603  delete padstack;
1604  }
1605 
1606  WIRE_VIA* dsnVia = new WIRE_VIA( pcb->wiring );
1607 
1608  pcb->wiring->wire_vias.push_back( dsnVia );
1609 
1610  dsnVia->padstack_id = registered->padstack_id;
1611  dsnVia->vertexes.push_back( mapPt( via->GetPosition() ) );
1612 
1613  NETINFO_ITEM* net = aBoard->FindNet( netcode );
1614  wxASSERT( net );
1615 
1616  dsnVia->net_id = TO_UTF8( net->GetNetname() );
1617 
1618  dsnVia->via_type = T_protect; // @todo, this should be configurable
1619  }
1620  }
1621 
1622 #endif // do existing wires and vias
1623 
1624  //-----<via_descriptor>-------------------------------------------------
1625  {
1626  // The pcb->library will output <padstack_descriptors> which is a combined
1627  // list of part padstacks and via padstacks. specctra dsn uses the
1628  // <via_descriptors> to say which of those padstacks are vias.
1629 
1630  // Output the vias in the padstack list here, by name only. This must
1631  // be done after exporting existing vias as WIRE_VIAs.
1632  VIA* vias = pcb->structure->via;
1633 
1634  for( unsigned viaNdx = 0; viaNdx < pcb->library->vias.size(); ++viaNdx )
1635  {
1636  vias->AppendVia( pcb->library->vias[viaNdx].padstack_id.c_str() );
1637  }
1638  }
1639 
1640 
1641  //-----<output NETCLASSs>----------------------------------------------------
1642  NETCLASSES& nclasses = aBoard->GetDesignSettings().m_NetClasses;
1643 
1644  exportNETCLASS( nclasses.GetDefault(), aBoard );
1645 
1646  for( NETCLASSES::iterator nc = nclasses.begin(); nc != nclasses.end(); ++nc )
1647  {
1648  NETCLASSPTR netclass = nc->second;
1649  exportNETCLASS( netclass, aBoard );
1650  }
1651 }
1652 
1653 
1654 void SPECCTRA_DB::exportNETCLASS( const NETCLASSPTR& aNetClass, BOARD* aBoard )
1655 {
1656  /* From page 11 of specctra spec:
1657  *
1658  * Routing and Placement Rule Hierarchies
1659  *
1660  * Routing and placement rules can be defined at multiple levels of design
1661  * specification. When a routing or placement rule is defined for an object at
1662  * multiple levels, a predefined routing or placement precedence order
1663  * automatically determines which rule to apply to the object. The routing rule
1664  * precedence order is
1665  *
1666  * pcb < layer < class < class layer < group_set < group_set layer < net <
1667  * net layer < group < group layer < fromto < fromto layer < class_class <
1668  * class_class layer < padstack < region < class region < net region <
1669  * class_class region
1670  *
1671  * A pcb rule (global rule for the PCB design) has the lowest precedence in the
1672  * hierarchy. A class-to-class region rule has the highest precedence. Rules
1673  * set at one level of the hierarchy override conflicting rules set at lower
1674  * levels. The placement rule precedence order is
1675  *
1676  * pcb < image_set < image < component < super cluster < room <
1677  * room_image_set < family_family < image_image
1678  *
1679  * A pcb rule (global rule for the PCB design) has the lowest precedence in the
1680  * hierarchy. An image-to-image rule has the highest precedence. Rules set at
1681  * one level of the hierarchy override conflicting rules set at lower levels.
1682  */
1683 
1684  char text[256];
1685 
1686  CLASS* clazz = new CLASS( pcb->network );
1687 
1688  pcb->network->classes.push_back( clazz );
1689 
1690  // freerouter creates a class named 'default' anyway, and if we
1691  // try and use that, we end up with two 'default' via rules so use
1692  // something else as the name of our default class.
1693  clazz->class_id = TO_UTF8( aNetClass->GetName() );
1694 
1695  for( NETCLASS::iterator net = aNetClass->begin(); net != aNetClass->end(); ++net )
1696  clazz->net_ids.push_back( TO_UTF8( *net ) );
1697 
1698  clazz->rules = new RULE( clazz, T_rule );
1699 
1700  // output the track width.
1701  int trackWidth = aNetClass->GetTrackWidth();
1702  sprintf( text, "(width %.6g)", scale( trackWidth ) );
1703  clazz->rules->rules.push_back( text );
1704 
1705  // output the clearance.
1706  int clearance = aNetClass->GetClearance();
1707  sprintf( text, "(clearance %.6g)", scale( clearance ) + safetyMargin );
1708  clazz->rules->rules.push_back( text );
1709 
1710  if( aNetClass->GetName() == NETCLASS::Default )
1711  {
1712  clazz->class_id = "kicad_default";
1713  }
1714 
1715  // the easiest way to get the via name is to create a via (which generates
1716  // the name internal to the PADSTACK), and then grab the name and then
1717  // delete the via. There are not that many netclasses so
1718  // this should never become a performance issue.
1719 
1720  PADSTACK* via = makeVia( aNetClass->GetViaDiameter(), aNetClass->GetViaDrill(),
1722 
1723  snprintf( text, sizeof(text), "(use_via %s)", via->GetPadstackId().c_str() );
1724  clazz->circuit.push_back( text );
1725 
1726  delete via;
1727 }
1728 
1729 
1731 {
1732  for( auto module : aBoard->Modules() )
1733  {
1734  module->SetFlag( 0 );
1735  if( module->GetLayer() == B_Cu )
1736  {
1737  module->Flip( module->GetPosition(), aBoard->GeneralSettings().m_FlipLeftRight );
1738  module->SetFlag( 1 );
1739  }
1740  }
1741 
1742  modulesAreFlipped = true;
1743 }
1744 
1745 
1747 {
1748  if( !modulesAreFlipped )
1749  return;
1750 
1751  // DSN Images (=KiCad MODULES and pads) must be presented from the
1752  // top view. Restore those that were flipped.
1753  for( auto module : aBoard->Modules() )
1754  {
1755  if( module->GetFlag() )
1756  {
1757  module->Flip( module->GetPosition(), aBoard->GeneralSettings().m_FlipLeftRight );
1758  module->SetFlag( 0 );
1759  }
1760  }
1761 
1762  modulesAreFlipped = false;
1763 }
1764 
1765 } // 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:686
VIA corresponds to the <via_descriptor> in the specctra dsn spec.
Definition: specctra.h:1011
void FixNegativeZero()
Function FixNegativeZero will change negative zero to positive zero in the IEEE floating point storag...
Definition: specctra.h:136
NETINFO_ITEM * FindNet(int aNetcode) const
Function FindNet searches for a net with the given netcode.
PIN_REF corresponds to the <pin_reference> definition in the specctra dsn spec.
Definition: specctra.h:2428
ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:60
static wxString ShowShape(STROKE_T aShape)
Function ShowShape converts the enum STROKE_T integer value to a wxString.
bool space_in_quoted_tokens
Definition: specctra.h:372
void SetAperture(double aWidth)
Definition: specctra.h:607
std::string pin_id
Definition: specctra.h:1929
void buildLayerMaps(BOARD *aBoard)
Function buildLayerMaps creates a few data translation structures for layer name and number mapping b...
Definition: specctra.cpp:74
static bool isRoundKeepout(D_PAD *aPad)
Function isRoundKeepout decides if the pad is a copper-less through hole which needs to be made into ...
DSN::T DSN_T
Definition: specctra.h:47
int GetNetCode() const
Function GetNetCode.
std::map< wxString, int > PINMAP
data type used to ensure unique-ness of pin names, holding (wxString and int)
int OutlineCount() const
Returns the number of outlines in the set
const wxPoint & GetPos0() const
Definition: class_pad.h:294
double GetLineLength(const wxPoint &aPointA, const wxPoint &aPointB)
Return the length of a line segment defined by aPointA and aPointB.
Definition: trigo.h:206
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: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
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:252
STRINGS circuit
circuit descriptor list
Definition: specctra.h:2730
This file is part of the common library TODO brief description.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: common.h:202
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:111
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:310
PADSTACKSET padstackset
Definition: specctra.h:3638
double GetOrientationDegrees() const
Definition: class_pad.h:427
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:102
virtual PCB_LAYER_ID GetLayer() const override
Function GetLayer returns the primary layer this item is on.
Definition: class_zone.cpp:213
int GetWidth() const
Definition: eda_rect.h:119
void SetLayerId(const char *aLayerId)
Definition: specctra.h:602
const wxString GetValue() const
Function GetValue.
Definition: class_module.h:461
void SetLayerId(const char *aLayerId)
Definition: specctra.h:753
static bool registered
Definition: coroutines.cpp:136
POINTS vertexes
Definition: specctra.h:2962
int kiNetCode
KiCad netcode.
Definition: specctra.h:1932
void fillBOUNDARY(BOARD *aBoard, BOUNDARY *aBoundary)
Function fillBOUNDARY makes the board perimeter for the DSN file by filling the BOUNDARY element in t...
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Returns the reference to aHole-th hole in the aIndex-th outline
UNIT_RES * resolution
Definition: specctra.h:3141
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:512
usual segment : line with rounded ends
void AppendPoint(const POINT &aPoint)
Definition: specctra.h:595
class D_PAD, a pad in a footprint
Definition: typeinfo.h:90
CLASS 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:219
PLACES places
Definition: specctra.h:1746
void NORMALIZE_ANGLE_DEGREES_POS(double &Angle)
Definition: trigo.h:275
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
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
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.
RULE corresponds to the <rule_descriptor> in the specctra dsn spec.
Definition: specctra.h:492
void SetVertex(const POINT &aVertex)
Definition: specctra.h:1718
std::set< std::string > STRINGSET
Definitions for tracks, vias and zones.
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
This file contains miscellaneous commonly used macros and functions.
void SetShape(ELEM *aShape)
Definition: specctra.h:852
PADSTACK * makePADSTACK(BOARD *aBoard, D_PAD *aPad)
Function makePADSTACK creates a PADSTACK which matches the given pad.
const wxString GetReference() const
Function GetReference.
Definition: class_module.h:436
static const KICAD_T scanPADs[]
Definition: specctra.h:3636
int GetChamferPositions() const
has meaning only for chamfered rect pads
Definition: class_pad.h:724
const char * c_str() const
Definition: utf8.h:107
bool GetDoNotAllowVias() const
Definition: class_zone.h:651
PATH supports both the <path_descriptor> and the <polygon_descriptor> per the specctra dsn spec.
Definition: specctra.h:576
std::pair< STRINGSET::iterator, bool > STRINGSET_PAIR
const wxPoint & GetStart0() const
const std::string & GetPadstackId()
Definition: specctra.h:2139
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:48
int GetCount() const
Function GetCount returns the number of objects in the list.
Definition: collector.h:100
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 Point()
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:
LSET is a set of PCB_LAYER_IDs.
iterator begin()
Definition: netclass.h:248
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
#define NULL
void AddWindow(WINDOW *aWindow)
Definition: specctra.h:944
unsigned GetNetCount() const
Function GetNetCount.
Definition: class_board.h:742
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
MODULES & Modules()
Definition: class_board.h:229
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
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
BASE_SCREEN handles how to draw a screen (a board, a schematic ...)
Definition: base_screen.h:74
Arcs (with rounded ends)
PLACE implements the <placement_reference> in the specctra dsn spec.
Definition: specctra.h:1659
const wxPoint & GetOffset() const
Definition: class_pad.h:309
double GetChamferRectRatio() const
has meaning only for chamfered rect pads
Definition: class_pad.h:701
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:446
Definition of file extensions used in Kicad.
const wxString & GetNetname() const
Function GetNetname.
Definition: netinfo.h:232
void AddPadstack(PADSTACK *aPadstack)
Definition: specctra.h:2254
const wxString & GetName() const
Definition: class_pad.h:203
double GetOrientationDegrees() const
Definition: class_module.h:216
std::string component_id
reference designator
Definition: specctra.h:1663
PADSTACK holds either a via or a pad definition.
Definition: specctra.h:2098
void Append(ELEM *aElem)
Definition: specctra.h:321
a few functions useful in geometry calculations.
WIRE_VIAS wire_vias
Definition: specctra.h:3099
#define THROW_IO_ERROR(msg)
bool IsModify() const
Definition: base_screen.h:228
int m_top_via_layer
specctra cu layers, 0 based index:
Definition: specctra.h:3644
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, wxString *aErrorText=nullptr, wxPoint *aErrorLocation=nullptr)
Function GetBoardPolygonOutlines Extracts the board outlines and build a closed polygon from lines,...
std::vector< std::string > STRINGS
Definition: specctra.h:158
const PCBNEW_SETTINGS & GeneralSettings() const
Definition: class_board.h:538
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:303
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
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:573
std::string padstack_id
Definition: specctra.h:1926
int GetHeight() const
Definition: eda_rect.h:120
UTF8 Format() const
Definition: lib_id.cpp:237
int GetWidth() const
bool GetIsKeepout() const
Accessors to parameters used in Keepout zones:
Definition: class_zone.h:649
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()
void TransformRoundChamferedRectToPolygon(SHAPE_POLY_SET &aCornerBuffer, const wxPoint &aPosition, const wxSize &aSize, double aRotation, int aCornerRadius, double aChamferRatio, int aChamferCorners, int aApproxErrorMax, int aMinSegPerCircleCount=16)
convert a rectangle with rounded corners and/or chamfered corners to a polygon Convert rounded corner...
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.
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
COMPONENT implements the <component_descriptor> in the specctra dsn spec.
Definition: specctra.h:1739
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:101
Struct POINT is a holder for a point in the SPECCTRA DSN coordinate system.
Definition: specctra.h:94
void FromBOARD(BOARD *aBoard)
Function FromBOARD adds the entire BOARD to the PCB but does not write it out.
int GetWidth() const
Definition: class_track.h:105
WIRE corresponds to <wire_shape_descriptor> in the specctra dsn spec.
Definition: specctra.h:2847
const char * name
Definition: DXF_plotter.cpp:60
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:224
void AppendVia(PADSTACK *aVia)
Function AppendVia adds aVia to the internal via container.
Definition: specctra.h:2347
BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:163
int GetFlag() const
Definition: class_module.h:264
DSN_T Type() const
Definition: specctra.h:231
POINTS points
Definition: specctra.h:583
#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:470
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
int GetCopperLayerCount() const
Function GetCopperLayerCount.
const wxSize & GetDrillSize() const
Definition: class_pad.h:306
static double mapX(int x)
const SHAPE_POLY_SET & GetCustomShapeAsPolygon() const
Accessor to the custom shape as one polygon.
Definition: class_pad.h:378
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
void ClrModify()
Definition: base_screen.h:225
void SetShape(ELEM *aShape)
Definition: specctra.h:2888
static bool empty(const wxTextEntryBase *aCtrl)
static double scale(int kicadDist)
Function scale converts a distance from PCBNEW internal units to the reported specctra dsn units in f...
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:61
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:108
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:577
bool GetDoNotAllowTracks() const
Definition: class_zone.h:652
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
LAYERS layers
Definition: specctra.h:1531
PIN_REFS pins
Definition: specctra.h:2577
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
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:237
Module description (excepted pads)
wxPoint m_Start0
Start point or center, relative to module origin, orient 0.
std::string pin_id
Definition: specctra.h:2431
DSN_T wire_type
Definition: specctra.h:2862
Collect all BOARD_ITEM objects of a given set of KICAD_T type(s).
Definition: collectors.h:621
std::vector< PCB_LAYER_ID > pcbLayer2kicad
maps PCB layer number to BOARD layer numbers
Definition: specctra.h:3628
const wxSize & GetSize() const
Definition: class_pad.h:300
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:746
PROPERTIES properties
Definition: specctra.h:1188
STRINGS net_ids
Definition: specctra.h:2727
EDGE_MODULE class definition.
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:210
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
void SetDiameter(double aDiameter)
Definition: specctra.h:758
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:229
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
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:1541