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