KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 <[email protected]>
5 * Copyright The 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 "specctra.h"
35
36#include <set>
37#include <map>
38
39#include <wx/log.h>
40
41#include <pcb_edit_frame.h>
42#include <confirm.h> // DisplayErrorMessage()
43#include <gestfich.h> // EDA_FileSelector()
44#include <locale_io.h>
45#include <macros.h>
46#include <math/util.h> // for KiROUND
47#include <string_utils.h>
48
49#include <board.h>
51#include <footprint.h>
52#include <pcb_shape.h>
53#include <pcb_track.h>
54#include <pad.h>
55#include <zone.h>
56#include <base_units.h>
57#include <collectors.h>
62#include <pcbnew_settings.h>
63
64
65using namespace DSN;
66
67// comment the line #define EXPORT_CUSTOM_PADS_CONVEX_HULL to export CUSTOM pads exact shapes.
68// Shapes can be non convex polygons with holes (linked to outline) that can create issues.
69// Especially Freerouter does not handle them very well:
70// - too complex shapes are not accepted, especially shapes with holes (dsn files are not loaded).
71// - and Freerouter actually uses something like a convex hull of the shape (that works poorly).
72// I am guessing non convex polygons with holes linked could create issues with any Router.
73#define EXPORT_CUSTOM_PADS_CONVEX_HULL
74
75
76bool PCB_EDIT_FRAME::ExportSpecctraFile( const wxString& aFullFilename )
77{
78 BASE_SCREEN* screen = GetScreen();
79 bool wasModified = screen->IsContentModified();
80 wxString errorText;
81 bool ok = true;
82
83 try
84 {
85 DSN::ExportBoardToSpecctraFile( GetBoard(), aFullFilename );
86 }
87 catch( const IO_ERROR& ioe )
88 {
89 ok = false;
90
91 // copy the error string to safe place, ioe is in this scope only.
92 errorText = ioe.What();
93 }
94
95 // The two calls to FOOTPRINT::Flip() in ExportBoardToSpecctraFile both set the modified flag,
96 // yet their actions cancel each other out, so it should be ok to clear the flag.
97 if( !wasModified )
98 screen->SetContentModified( false );
99
100 if( ok )
101 SetStatusText( wxString( _( "BOARD exported OK." ) ) );
102 else
103 DisplayErrorMessage( this, _( "Unable to export, please fix and try again" ), errorText );
104
105 return ok;
106}
107
108namespace DSN
109{
110
111
112void ExportBoardToSpecctraFile( BOARD* aBoard, const wxString& aFullFilename )
113{
114 SPECCTRA_DB db;
115
117
118 LOCALE_IO toggle; // Switch the locale to standard C
119
120 // Build the board outlines *before* flipping footprints
121 if( !db.BuiltBoardOutlines( aBoard ) )
122 wxLogWarning( _( "Board outline is malformed. Run DRC for a full analysis." ) );
123
124 // DSN Images (=KiCad FOOTPRINTs and PADs) must be presented from the top view. So we
125 // temporarily flip any footprints which are on the back side of the board to the front,
126 // and record this in the FOOTPRINT's flag field.
127 db.FlipFOOTPRINTs( aBoard );
128
129 try
130 {
131 aBoard->SynchronizeNetsAndNetClasses( false );
132 db.FromBOARD( aBoard );
133 db.ExportPCB( aFullFilename, true );
134 db.RevertFOOTPRINTs( aBoard );
135
136 // if an exception is thrown by FromBOARD() or ExportPCB(), then ~SPECCTRA_DB() will
137 // close the file.
138 }
139 catch( ... )
140 {
141 db.RevertFOOTPRINTs( aBoard );
142 throw;
143 }
144}
145
146
147// "specctra reported units" are what we tell the external router that our exported lengths are in
148
153static inline double scale( int kicadDist )
154{
155 // nanometers to um
156 return kicadDist / ( pcbIUScale.IU_PER_MM / 1000.0 );
157}
158
159
161static inline double IU2um( int kicadDist )
162{
163 return kicadDist * ( 1000.0 / pcbIUScale.IU_PER_MM );
164}
165
166
167static inline double mapX( int x )
168{
169 return scale( x );
170}
171
172
173static inline double mapY( int y )
174{
175 return -scale( y ); // make y negative, since it is increasing going down.
176}
177
178
185static POINT mapPt( const VECTOR2I& pt )
186{
187 POINT ret;
188
189 ret.x = mapX( pt.x );
190 ret.y = mapY( pt.y );
191 ret.FixNegativeZero();
192 return ret;
193}
194
195
196static POINT mapPt( const VECTOR2I& pt, FOOTPRINT* aFootprint )
197{
198 VECTOR2I fpRelative = pt - aFootprint->GetPosition();
199 RotatePoint( fpRelative, -aFootprint->GetOrientation() );
200 return mapPt( fpRelative );
201}
202
203
207static bool isRoundKeepout( PAD* aPad )
208{
209 // TODO(JE) padstacks
211 {
212 if( aPad->GetDrillSize().x >= aPad->GetSize( ::PADSTACK::ALL_LAYERS ).x )
213 return true;
214
215 if( !( aPad->GetLayerSet() & LSET::AllCuMask() ).any() )
216 return true;
217 }
218
219 return false;
220}
221
222
226static PATH* makePath( const POINT& aStart, const POINT& aEnd, const std::string& aLayerName )
227{
228 PATH* path = new PATH( nullptr, T_path );
229
230 path->AppendPoint( aStart );
231 path->AppendPoint( aEnd );
232 path->SetLayerId( aLayerName );
233 return path;
234}
235
236
238{
239 return aBoard->GetBoardPolygonOutlines( m_brd_outlines );
240}
241
242
244{
245 std::string uniqifier;
246
247 // caller must do these checks before calling here.
248 wxASSERT( !isRoundKeepout( aPad ) );
249
250 PADSTACK* padstack = new PADSTACK();
251
252 uniqifier = '[';
253
254 const int copperCount = aBoard->GetCopperLayerCount();
255 static const LSET all_cu = LSET::AllCuMask( copperCount );
256 int reportedLayers = 0;
257 std::vector<std::string> layerName( copperCount );
258
259 bool onAllCopperLayers = ( (aPad->GetLayerSet() & all_cu) == all_cu );
260
261 if( onAllCopperLayers )
262 uniqifier += 'A'; // A for all layers
263
264 for( int layer=0; layer < copperCount; ++layer )
265 {
266 PCB_LAYER_ID kilayer = m_pcbLayer2kicad[layer];
267
268 if( onAllCopperLayers || aPad->IsOnLayer( kilayer ) )
269 {
270 layerName[reportedLayers++] = m_layerIds[layer];
271
272 if( !onAllCopperLayers )
273 {
274 if( layer == 0 )
275 uniqifier += 'T';
276 else if( layer == copperCount - 1 )
277 uniqifier += 'B';
278 else
279 uniqifier += char('0' + layer); // layer index char
280 }
281 }
282 }
283
284 uniqifier += ']';
285
286 POINT dsnOffset;
287
288 // TODO(JE) padstacks
289 const VECTOR2I& padSize = aPad->GetSize( ::PADSTACK::ALL_LAYERS );
290 const VECTOR2I& offset = aPad->GetOffset( ::PADSTACK::ALL_LAYERS );
291
292 if( offset.x || offset.y )
293 {
294 dsnOffset = mapPt( offset );
295 // Using () would cause padstack name to be quoted, and {} locks freerouter, so use [].
296 std::ostringstream oss;
297 oss.imbue( std::locale::classic() );
298 oss << std::fixed << std::setprecision( 6 )
299 << '[' << dsnOffset.x << ',' << dsnOffset.y << ']';
300 uniqifier += oss.str();
301 }
302
303 switch( aPad->GetShape( ::PADSTACK::ALL_LAYERS ) )
304 {
306 {
307 double diameter = scale( padSize.x );
308
309 for( int ndx = 0; ndx < reportedLayers; ++ndx )
310 {
311 SHAPE* shape = new SHAPE( padstack );
312
313 padstack->Append( shape );
314
315 CIRCLE* circle = new CIRCLE( shape );
316
317 shape->SetShape( circle );
318
319 circle->SetLayerId( layerName[ndx] );
320 circle->SetDiameter( diameter );
321 circle->SetVertex( dsnOffset );
322 }
323
324 std::ostringstream oss;
325 oss << "Round" << uniqifier << "Pad_" << std::fixed << std::setprecision(6)
326 << IU2um( padSize.x ) << "_um";
327
328 padstack->SetPadstackId( oss.str().c_str() );
329 break;
330 }
331
333 {
334 double dx = scale( padSize.x ) / 2.0;
335 double dy = scale( padSize.y ) / 2.0;
336
337 POINT lowerLeft( -dx, -dy );
338 POINT upperRight( dx, dy );
339
340 lowerLeft += dsnOffset;
341 upperRight += dsnOffset;
342
343 for( int ndx = 0; ndx < reportedLayers; ++ndx )
344 {
345 SHAPE* shape = new SHAPE( padstack );
346
347 padstack->Append( shape );
348
349 RECTANGLE* rect = new RECTANGLE( shape );
350
351 shape->SetShape( rect );
352
353 rect->SetLayerId( layerName[ndx] );
354 rect->SetCorners( lowerLeft, upperRight );
355 }
356
357 std::ostringstream oss;
358 oss << "Rect" << uniqifier << "Pad_" << std::fixed << std::setprecision(6)
359 << IU2um( padSize.x ) << "x" << IU2um( padSize.y ) << "_um";
360
361 padstack->SetPadstackId( oss.str().c_str() );
362 break;
363 }
364
365 case PAD_SHAPE::OVAL:
366 {
367 double dx = scale( padSize.x ) / 2.0;
368 double dy = scale( padSize.y ) / 2.0;
369 double dr = dx - dy;
370 double radius;
371 POINT pstart;
372 POINT pstop;
373
374 if( dr >= 0 ) // oval is horizontal
375 {
376 radius = dy;
377
378 pstart = POINT( -dr, 0.0 );
379 pstop = POINT( dr, 0.0 );
380 }
381 else // oval is vertical
382 {
383 radius = dx;
384 dr = -dr;
385
386 pstart = POINT( 0.0, -dr );
387 pstop = POINT( 0.0, dr );
388 }
389
390 pstart += dsnOffset;
391 pstop += dsnOffset;
392
393 for( int ndx = 0; ndx < reportedLayers; ++ndx )
394 {
395 SHAPE* shape;
396 PATH* path;
397
398 // see http://www.freerouting.net/usren/viewtopic.php?f=3&t=317#p408
399 shape = new SHAPE( padstack );
400
401 padstack->Append( shape );
402 path = makePath( pstart, pstop, layerName[ndx] );
403 shape->SetShape( path );
404 path->aperture_width = 2.0 * radius;
405 }
406
407 std::ostringstream oss;
408 oss << "Oval" << uniqifier << "Pad_" << std::fixed << std::setprecision(6)
409 << IU2um( padSize.x ) << "x" << IU2um( padSize.y ) << "_um";
410
411 padstack->SetPadstackId( oss.str().c_str() );
412 break;
413 }
414
416 {
417 double dx = scale( padSize.x ) / 2.0;
418 double dy = scale( padSize.y ) / 2.0;
419
421
422 double ddx = scale( delta.x ) / 2.0;
423 double ddy = scale( delta.y ) / 2.0;
424
425 // see class_pad_draw_functions.cpp which draws the trapezoid pad
426 POINT lowerLeft( -dx - ddy, -dy - ddx );
427 POINT upperLeft( -dx + ddy, +dy + ddx );
428 POINT upperRight( +dx - ddy, +dy - ddx );
429 POINT lowerRight( +dx + ddy, -dy + ddx );
430
431 lowerLeft += dsnOffset;
432 upperLeft += dsnOffset;
433 upperRight += dsnOffset;
434 lowerRight += dsnOffset;
435
436 for( int ndx = 0; ndx < reportedLayers; ++ndx )
437 {
438 SHAPE* shape = new SHAPE( padstack );
439
440 padstack->Append( shape );
441
442 // a T_polygon exists as a PATH
443 PATH* polygon = new PATH( shape, T_polygon );
444
445 shape->SetShape( polygon );
446
447 polygon->SetLayerId( layerName[ndx] );
448
449 polygon->AppendPoint( lowerLeft );
450 polygon->AppendPoint( upperLeft );
451 polygon->AppendPoint( upperRight );
452 polygon->AppendPoint( lowerRight );
453 }
454
455 // this string _must_ be unique for a given physical shape
456 std::ostringstream oss;
457 oss << "Trapz" << uniqifier << "Pad_" << std::fixed << std::setprecision(6)
458 << IU2um( padSize.x ) << "x" << IU2um( padSize.y ) << "_"
459 << ( delta.x < 0 ? "n" : "p") << std::abs( IU2um( delta.x ) ) << "x"
460 << ( delta.y < 0 ? "n" : "p") << std::abs( IU2um( delta.y ) ) << "_um";
461
462 padstack->SetPadstackId( oss.str().c_str() );
463 break;
464 }
465
468 {
469 // Export the shape as as polygon, round rect does not exist as primitive
470 const int circleToSegmentsCount = 36;
472 SHAPE_POLY_SET cornerBuffer;
473
474 // Use a slightly bigger shape because the round corners are approximated by
475 // segments, giving to the polygon a slightly smaller shape than the actual shape
476
477 /* calculates the coeff to compensate radius reduction of holes clearance
478 * due to the segment approx.
479 * For a circle the min radius is radius * cos( 2PI / s_CircleToSegmentsCount / 2)
480 * correctionFactor is cos( PI/s_CircleToSegmentsCount )
481 */
482 double correctionFactor = cos( M_PI / (double) circleToSegmentsCount );
483 int extra_clearance = KiROUND( rradius * ( 1.0 - correctionFactor ) );
484 VECTOR2I psize = padSize;
485 psize.x += extra_clearance * 2;
486 psize.y += extra_clearance * 2;
487 rradius += extra_clearance;
488 bool doChamfer = aPad->GetShape( ::PADSTACK::ALL_LAYERS ) == PAD_SHAPE::CHAMFERED_RECT;
489
490 TransformRoundChamferedRectToPolygon( cornerBuffer, VECTOR2I( 0, 0 ), psize, ANGLE_0,
492 doChamfer ? aPad->GetChamferPositions( ::PADSTACK::ALL_LAYERS ) : 0,
493 0, aPad->GetMaxError(), ERROR_INSIDE );
494
495 SHAPE_LINE_CHAIN& polygonal_shape = cornerBuffer.Outline( 0 );
496
497 for( int ndx = 0; ndx < reportedLayers; ++ndx )
498 {
499 SHAPE* shape = new SHAPE( padstack );
500
501 padstack->Append( shape );
502
503 // a T_polygon exists as a PATH
504 PATH* polygon = new PATH( shape, T_polygon );
505
506 shape->SetShape( polygon );
507
508 polygon->SetLayerId( layerName[ndx] );
509
510 // append a closed polygon
511 POINT first_corner;
512
513 for( int idx = 0; idx < polygonal_shape.PointCount(); idx++ )
514 {
515 POINT corner( scale( polygonal_shape.CPoint( idx ).x ),
516 scale( -polygonal_shape.CPoint( idx ).y ) );
517 corner += dsnOffset;
518 polygon->AppendPoint( corner );
519
520 if( idx == 0 )
521 first_corner = corner;
522 }
523
524 polygon->AppendPoint( first_corner ); // Close polygon
525 }
526
527 // this string _must_ be unique for a given physical shape
528 std::ostringstream oss;
529 oss << "RoundRect" << uniqifier << "Pad_"
530 << std::fixed << std::setprecision(6)
531 << IU2um( padSize.x ) << 'x'
532 << IU2um( padSize.y ) << '_'
533 << IU2um( rradius ) << "_um_"
534 << ( doChamfer ? aPad->GetChamferRectRatio( ::PADSTACK::ALL_LAYERS ) : 0.0 ) << '_'
535 << std::hex << std::uppercase
536 << ( doChamfer ? aPad->GetChamferPositions( ::PADSTACK::ALL_LAYERS ) : 0 );
537
538 padstack->SetPadstackId( oss.str().c_str() );
539 break;
540 }
541
543 {
544 std::vector<VECTOR2I> polygonal_shape;
545 SHAPE_POLY_SET pad_shape;
547
548#ifdef EXPORT_CUSTOM_PADS_CONVEX_HULL
549 BuildConvexHull( polygonal_shape, pad_shape );
550#else
551 const SHAPE_LINE_CHAIN& p_outline = pad_shape.COutline( 0 );
552
553 for( int ii = 0; ii < p_outline.PointCount(); ++ii )
554 polygonal_shape.push_back( wxPoint( p_outline.CPoint( ii ) ) );
555#endif
556
557 // The polygon must be closed
558 if( polygonal_shape.front() != polygonal_shape.back() )
559 polygonal_shape.push_back( polygonal_shape.front() );
560
561 for( int ndx = 0; ndx < reportedLayers; ++ndx )
562 {
563 SHAPE* shape = new SHAPE( padstack );
564
565 padstack->Append( shape );
566
567 // a T_polygon exists as a PATH
568 PATH* polygon = new PATH( shape, T_polygon );
569
570 shape->SetShape( polygon );
571
572 polygon->SetLayerId( layerName[ndx] );
573
574 for( unsigned idx = 0; idx < polygonal_shape.size(); idx++ )
575 {
576 POINT corner( scale( polygonal_shape[idx].x ), scale( -polygonal_shape[idx].y ) );
577 corner += dsnOffset;
578 polygon->AppendPoint( corner );
579 }
580 }
581
582 // this string _must_ be unique for a given physical shape, so try to make it unique
583 const HASH_128 hash = pad_shape.GetHash();
584 const BOX2I rect = aPad->GetBoundingBox();
585
586 std::ostringstream oss;
587 oss << "Cust" << uniqifier << "Pad_"
588 << std::fixed << std::setprecision(6)
589 << IU2um( padSize.x ) << 'x' << IU2um( padSize.y ) << '_'
590 << IU2um( rect.GetWidth() ) << 'x' << IU2um( rect.GetHeight() ) << '_'
591 << polygonal_shape.size() << "_um_"
592 << hash.ToString();
593
594 padstack->SetPadstackId( oss.str().c_str() );
595 break;
596 }
597 }
598
599 return padstack;
600}
601
602
604typedef std::map<wxString, int> PINMAP;
605
606
608{
609 PINMAP pinmap;
610 wxString padNumber;
611
612 PCB_TYPE_COLLECTOR fpItems;
613
614 // get all the FOOTPRINT's pads.
615 fpItems.Collect( aFootprint, { PCB_PAD_T } );
616
617 IMAGE* image = new IMAGE( nullptr );
618
619 image->m_image_id = aFootprint->GetFPID().Format().c_str();
620
621 // from the pads, and make an IMAGE using collated padstacks.
622 for( int p = 0; p < fpItems.GetCount(); ++p )
623 {
624 PAD* pad = (PAD*) fpItems[p];
625
626 // see if this pad is a through hole with no copper on its perimeter
627 if( isRoundKeepout( pad ) )
628 {
629 double diameter = scale( pad->GetDrillSize().x );
630 POINT vertex = mapPt( pad->GetFPRelativePosition() );
631
632 diameter += scale( aBoard->GetDesignSettings().m_HoleClearance * 2 );
633
634 int layerCount = aBoard->GetCopperLayerCount();
635
636 for( int layer=0; layer<layerCount; ++layer )
637 {
638 KEEPOUT* keepout = new KEEPOUT( image, T_keepout );
639
640 image->m_keepouts.push_back( keepout );
641
642 CIRCLE* circle = new CIRCLE( keepout );
643
644 keepout->SetShape( circle );
645
646 circle->SetDiameter( diameter );
647 circle->SetVertex( vertex );
648 circle->SetLayerId( m_layerIds[layer] );
649 }
650 }
651 else // else if() could there be a square keepout here?
652 {
653 // Pads not on copper layers (i.e. only on tech layers) are ignored
654 // because they create invalid pads in .dsn file for freeroute
655 LSET mask_copper_layers = pad->GetLayerSet() & LSET::AllCuMask();
656
657 if( !mask_copper_layers.any() )
658 continue;
659
660 PADSTACK* padstack = makePADSTACK( aBoard, pad );
661 PADSTACKSET::iterator iter = m_padstackset.find( *padstack );
662
663 if( iter != m_padstackset.end() )
664 {
665 // padstack is a duplicate, delete it and use the original
666 delete padstack;
667 padstack = (PADSTACK*) *iter.base(); // folklore, be careful here
668 }
669 else
670 {
671 m_padstackset.insert( padstack );
672 }
673
674 PIN* pin = new PIN( image );
675
676 padNumber = pad->GetNumber();
677 pin->m_pin_id = TO_UTF8( padNumber );
678
679 if( padNumber != wxEmptyString && pinmap.find( padNumber ) == pinmap.end() )
680 {
681 pinmap[ padNumber ] = 0;
682 }
683 else // pad name is a duplicate within this footprint
684 {
685 int duplicates = ++pinmap[ padNumber ];
686
687 pin->m_pin_id +=
688 "@" + std::to_string( duplicates ); // append "@1" or "@2", etc. to pin name
689 }
690
691 pin->m_kiNetCode = pad->GetNetCode();
692
693 image->m_pins.push_back( pin );
694
695 pin->m_padstack_id = padstack->m_padstack_id;
696
697 EDA_ANGLE angle = pad->GetOrientation() - aFootprint->GetOrientation();
698 pin->SetRotation( angle.Normalize().AsDegrees() );
699
700 VECTOR2I pos( pad->GetFPRelativePosition() );
701
702 pin->SetVertex( mapPt( pos ) );
703 }
704 }
705
706 // get all the FOOTPRINT's SHAPEs and convert those to DSN outlines.
707 fpItems.Collect( aFootprint, { PCB_SHAPE_T } );
708
709 for( int i = 0; i < fpItems.GetCount(); ++i )
710 {
711 PCB_SHAPE* graphic = static_cast<PCB_SHAPE*>( fpItems[i] );
712 SHAPE* outline;
713 PATH* path;
714
715 switch( graphic->GetShape() )
716 {
717 case SHAPE_T::SEGMENT:
718 outline = new SHAPE( image, T_outline );
719
720 image->Append( outline );
721 path = new PATH( outline );
722
723 outline->SetShape( path );
724 path->SetAperture( scale( graphic->GetWidth() ) );
725 path->SetLayerId( "signal" );
726 path->AppendPoint( mapPt( graphic->GetStart(), aFootprint ) );
727 path->AppendPoint( mapPt( graphic->GetEnd(), aFootprint ) );
728 break;
729
730 case SHAPE_T::CIRCLE:
731 {
732 // this is best done by 4 QARC's but freerouter does not yet support QARCs.
733 // for now, support by using line segments.
734 outline = new SHAPE( image, T_outline );
735 image->Append( outline );
736
737 path = new PATH( outline );
738
739 outline->SetShape( path );
740 path->SetAperture( scale( graphic->GetWidth() ) );
741 path->SetLayerId( "signal" );
742
743 double radius = graphic->GetRadius();
744 VECTOR2I circle_centre = graphic->GetStart();
745
746 SHAPE_LINE_CHAIN polyline;
747 ConvertArcToPolyline( polyline, VECTOR2I( circle_centre ), radius, ANGLE_0, ANGLE_360,
749
750 for( int ii = 0; ii < polyline.PointCount(); ++ii )
751 {
752 VECTOR2I corner( polyline.CPoint( ii ).x, polyline.CPoint( ii ).y );
753 path->AppendPoint( mapPt( corner, aFootprint ) );
754 }
755
756 break;
757 }
758
760 {
761 outline = new SHAPE( image, T_outline );
762
763 image->Append( outline );
764 path = new PATH( outline );
765
766 outline->SetShape( path );
767 path->SetAperture( scale( graphic->GetWidth() ) );
768 path->SetLayerId( "signal" );
769 VECTOR2I corner = graphic->GetStart();
770 path->AppendPoint( mapPt( corner, aFootprint ) );
771
772 corner.x = graphic->GetEnd().x;
773 path->AppendPoint( mapPt( corner, aFootprint ) );
774
775 corner.y = graphic->GetEnd().y;
776 path->AppendPoint( mapPt( corner, aFootprint ) );
777
778 corner.x = graphic->GetStart().x;
779 path->AppendPoint( mapPt( corner, aFootprint ) );
780 break;
781 }
782
783 case SHAPE_T::ARC:
784 {
785 // this is best done by QARC's but freerouter does not yet support QARCs.
786 // for now, support by using line segments.
787 // So we use a polygon (PATH) to create a approximate arc shape
788 outline = new SHAPE( image, T_outline );
789
790 image->Append( outline );
791 path = new PATH( outline );
792
793 outline->SetShape( path );
794 path->SetAperture( 0 );//scale( graphic->GetWidth() ) );
795 path->SetLayerId( "signal" );
796
797 VECTOR2I arc_centre = graphic->GetCenter();
798 double radius = graphic->GetRadius() + graphic->GetWidth()/2;
799 EDA_ANGLE arcAngle = graphic->GetArcAngle();
800
801 VECTOR2I startRadial = graphic->GetStart() - graphic->GetCenter();
802 EDA_ANGLE arcStart( startRadial );
803
804 arcStart.Normalize();
805
806 // For some obscure reason, FreeRouter does not show the same polygonal
807 // shape for polygons CW and CCW. So used only the order of corners
808 // giving the best look.
809 if( arcAngle < ANGLE_0 )
810 {
811 VECTOR2I endRadial = graphic->GetEnd() - graphic->GetCenter();
812 arcStart = EDA_ANGLE( endRadial );
813 arcStart.Normalize();
814
815 arcAngle = -arcAngle;
816 }
817
818 SHAPE_LINE_CHAIN polyline;
819 ConvertArcToPolyline( polyline, VECTOR2I( arc_centre ), radius, arcStart, arcAngle,
821
822 SHAPE_POLY_SET polyBuffer;
823 polyBuffer.AddOutline( polyline );
824
825 radius -= graphic->GetWidth();
826
827 if( radius > 0 )
828 {
829 polyline.Clear();
830 ConvertArcToPolyline( polyline, VECTOR2I( arc_centre ), radius, arcStart, arcAngle,
832
833 // Add points in reverse order, to create a closed polygon
834 for( int ii = polyline.PointCount() - 1; ii >= 0; --ii )
835 polyBuffer.Append( polyline.CPoint( ii ) );
836 }
837
838 // ensure the polygon is closed
839 polyBuffer.Append( polyBuffer.Outline( 0 ).CPoint( 0 ) );
840
841 VECTOR2I move = graphic->GetCenter() - arc_centre;
842
843 TransformCircleToPolygon( polyBuffer, graphic->GetStart() - move,
844 graphic->GetWidth() / 2, ARC_HIGH_DEF, ERROR_INSIDE );
845
846 TransformCircleToPolygon( polyBuffer, graphic->GetEnd() - move,
847 graphic->GetWidth() / 2, ARC_HIGH_DEF, ERROR_INSIDE );
848
849 polyBuffer.Simplify();
850 SHAPE_LINE_CHAIN& poly = polyBuffer.Outline( 0 );
851
852 for( int ii = 0; ii < poly.PointCount(); ++ii )
853 {
854 VECTOR2I corner( poly.CPoint( ii ).x, poly.CPoint( ii ).y );
855 path->AppendPoint( mapPt( corner, aFootprint ) );
856 }
857
858 break;
859 }
860
861 default:
862 continue;
863 }
864 }
865
866 for( ZONE* zone : aFootprint->Zones() )
867 {
868 if( !zone->GetIsRuleArea() )
869 continue;
870
871 // IMAGE object coordinates are relative to the IMAGE not absolute board coordinates.
872 ZONE untransformedZone( *zone );
873
874 EDA_ANGLE angle = -aFootprint->GetOrientation();
875 angle.Normalize();
876 untransformedZone.Rotate( aFootprint->GetPosition(), angle );
877
878 // keepout areas have a type. types are
879 // T_place_keepout, T_via_keepout, T_wire_keepout,
880 // T_bend_keepout, T_elongate_keepout, T_keepout.
881 // Pcbnew knows only T_keepout, T_via_keepout and T_wire_keepout
882 DSN_T keepout_type;
883
884 if( zone->GetDoNotAllowVias() && zone->GetDoNotAllowTracks() )
885 keepout_type = T_keepout;
886 else if( zone->GetDoNotAllowVias() )
887 keepout_type = T_via_keepout;
888 else if( zone->GetDoNotAllowTracks() )
889 keepout_type = T_wire_keepout;
890 else
891 keepout_type = T_keepout;
892
893 // Now, build keepout polygon on each copper layer where the zone
894 // keepout is living (keepout zones can live on many copper layers)
895 LSET layerset = zone->GetLayerSet() & LSET::AllCuMask( aBoard->GetCopperLayerCount() );
896
897 for( PCB_LAYER_ID layer : layerset.CuStack() )
898 {
899 KEEPOUT* keepout = new KEEPOUT( m_pcb->m_structure, keepout_type );
900 image->m_keepouts.push_back( keepout );
901
902 PATH* mainPolygon = new PATH( keepout, T_polygon );
903 keepout->SetShape( mainPolygon );
904
905 mainPolygon->layer_id = m_layerIds[ m_kicadLayer2pcb[ layer ] ];
906
907 // Handle the main outlines
909 bool is_first_point = true;
910 VECTOR2I startpoint;
911
912 for( iterator = untransformedZone.IterateWithHoles(); iterator; iterator++ )
913 {
914 VECTOR2I point( iterator->x, iterator->y );
915
916 point -= aFootprint->GetPosition();
917
918 if( is_first_point )
919 {
920 startpoint = point;
921 is_first_point = false;
922 }
923
924 mainPolygon->AppendPoint( mapPt( point ) );
925
926 // this was the end of the main polygon
927 if( iterator.IsEndContour() )
928 {
929 mainPolygon->AppendPoint( mapPt( startpoint ) );
930 break;
931 }
932 }
933
934 WINDOW* window = nullptr;
935 PATH* cutout = nullptr;
936 bool isStartContour = true;
937
938 // handle the cutouts
939 for( iterator++; iterator; iterator++ )
940 {
941 if( isStartContour )
942 {
943 is_first_point = true;
944 window = new WINDOW( keepout );
945 keepout->AddWindow( window );
946
947 cutout = new PATH( window, T_polygon );
948
949 window->SetShape( cutout );
950
951 cutout->layer_id = m_layerIds[ m_kicadLayer2pcb[ zone->GetLayer() ] ];
952 }
953
954 isStartContour = iterator.IsEndContour();
955
956 wxASSERT( window );
957 wxASSERT( cutout );
958
959 VECTOR2I point( iterator->x, iterator->y );
960
961 point -= aFootprint->GetPosition();
962
963 if( is_first_point )
964 {
965 startpoint = point;
966 is_first_point = false;
967 }
968
969 cutout->AppendPoint( mapPt( point ) );
970
971 // Close the polygon
972 if( iterator.IsEndContour() )
973 cutout->AppendPoint( mapPt( startpoint ) );
974 }
975 }
976 }
977
978 return image;
979}
980
981
982PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter, int aDrillDiameter,
983 int aTopLayer, int aBotLayer )
984{
985 char name[48];
986 PADSTACK* padstack = new PADSTACK();
987 double dsnDiameter = scale( aCopperDiameter );
988
989 for( int layer=aTopLayer; layer<=aBotLayer; ++layer )
990 {
991 SHAPE* shape = new SHAPE( padstack );
992
993 padstack->Append( shape );
994
995 CIRCLE* circle = new CIRCLE( shape );
996
997 shape->SetShape( circle );
998
999 circle->SetDiameter( dsnDiameter );
1000 circle->SetLayerId( m_layerIds[layer] );
1001 }
1002
1003 snprintf( name, sizeof( name ), "Via[%d-%d]_%.6g:%.6g_um",
1004 aTopLayer, aBotLayer, dsnDiameter,
1005 // encode the drill value into the name for later import
1006 IU2um( aDrillDiameter ) );
1007
1008 name[ sizeof(name) - 1 ] = 0;
1009 padstack->SetPadstackId( name );
1010
1011 return padstack;
1012}
1013
1014
1016{
1017 PCB_LAYER_ID topLayerNum;
1018 PCB_LAYER_ID botLayerNum;
1019
1020 aVia->LayerPair( &topLayerNum, &botLayerNum );
1021
1022 int topLayer = m_kicadLayer2pcb[topLayerNum];
1023 int botLayer = m_kicadLayer2pcb[botLayerNum];
1024
1025 if( topLayer > botLayer )
1026 std::swap( topLayer, botLayer );
1027
1028 // TODO(JE) padstacks
1029 return makeVia( aVia->GetWidth( ::PADSTACK::ALL_LAYERS ), aVia->GetDrillValue(),
1030 topLayer, botLayer );
1031}
1032
1033
1034void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary )
1035{
1036 for( int cnt = 0; cnt < m_brd_outlines.OutlineCount(); cnt++ ) // Should be one outline
1037 {
1038 PATH* path = new PATH( boundary );
1039 boundary->paths.push_back( path );
1040 path->layer_id = "pcb";
1041
1042 SHAPE_LINE_CHAIN& outline = m_brd_outlines.Outline( cnt );
1043
1044 for( int ii = 0; ii < outline.PointCount(); ii++ )
1045 {
1046 VECTOR2I pos( outline.CPoint( ii ).x, outline.CPoint( ii ).y );
1047 path->AppendPoint( mapPt( pos ) );
1048 }
1049
1050 // Close polygon:
1051 VECTOR2I pos0( outline.CPoint( 0 ).x, outline.CPoint( 0 ).y );
1052 path->AppendPoint( mapPt( pos0 ) );
1053
1054 // Generate holes as keepout:
1055 for( int ii = 0; ii < m_brd_outlines.HoleCount( cnt ); ii++ )
1056 {
1057 // emit a signal layers keepout for every interior polygon left...
1058 KEEPOUT* keepout = new KEEPOUT( nullptr, T_keepout );
1059 PATH* poly_ko = new PATH( nullptr, T_polygon );
1060
1061 keepout->SetShape( poly_ko );
1062 poly_ko->SetLayerId( "signal" );
1063 m_pcb->m_structure->m_keepouts.push_back( keepout );
1064
1065 SHAPE_LINE_CHAIN& hole = m_brd_outlines.Hole( cnt, ii );
1066
1067 for( int jj = 0; jj < hole.PointCount(); jj++ )
1068 {
1069 VECTOR2I pos( hole.CPoint( jj ).x, hole.CPoint( jj ).y );
1070 poly_ko->AppendPoint( mapPt( pos ) );
1071 }
1072
1073 // Close polygon:
1074 VECTOR2I pos( hole.CPoint( 0 ).x, hole.CPoint( 0 ).y );
1075 poly_ko->AppendPoint( mapPt( pos ) );
1076 }
1077 }
1078}
1079
1080
1081typedef std::set<std::string> STRINGSET;
1082typedef std::pair<STRINGSET::iterator, bool> STRINGSET_PAIR;
1083
1084
1086{
1087 std::shared_ptr<NET_SETTINGS>& netSettings = aBoard->GetDesignSettings().m_NetSettings;
1088
1089 // Not all boards are exportable. Check that all reference Ids are unique, or we won't be
1090 // able to import the session file which comes back to us later from the router.
1091 {
1092 STRINGSET refs; // holds footprint reference designators
1093
1094 for( FOOTPRINT* footprint : aBoard->Footprints() )
1095 {
1096 if( footprint->GetReference() == wxEmptyString )
1097 {
1098 THROW_IO_ERROR( wxString::Format( _( "Footprint with value of '%s' has an empty "
1099 "reference designator." ),
1100 footprint->GetValue() ) );
1101 }
1102
1103 // if we cannot insert OK, that means the reference has been seen before.
1104 STRINGSET_PAIR refpair = refs.insert( TO_UTF8( footprint->GetReference() ) );
1105
1106 if( !refpair.second ) // insert failed
1107 {
1108 THROW_IO_ERROR( wxString::Format( _( "Multiple footprints have the reference "
1109 "designator '%s'." ),
1110 footprint->GetReference() ) );
1111 }
1112 }
1113 }
1114
1115 if( !m_pcb )
1117
1118 //-----<layer_descriptor>-----------------------------------------------
1119 {
1120 // Specctra wants top physical layer first, then going down to the bottom most physical
1121 // layer in physical sequence.
1122
1123 buildLayerMaps( aBoard );
1124
1125 int layerCount = aBoard->GetCopperLayerCount();
1126
1127 for( int pcbNdx=0; pcbNdx<layerCount; ++pcbNdx )
1128 {
1129 LAYER* layer = new LAYER( m_pcb->m_structure );
1130
1131 m_pcb->m_structure->m_layers.push_back( layer );
1132
1133 layer->name = m_layerIds[pcbNdx];
1134
1135 DSN_T layerType;
1136
1137 switch( aBoard->GetLayerType( m_pcbLayer2kicad[pcbNdx] ) )
1138 {
1139 default:
1140 case LT_SIGNAL: layerType = T_signal; break;
1141 case LT_POWER: layerType = T_power; break;
1142
1143 // Freerouter does not support type "mixed", only signal and power.
1144 // Remap "mixed" to "signal".
1145 case LT_MIXED: layerType = T_signal; break;
1146 case LT_JUMPER: layerType = T_jumper; break;
1147 }
1148
1149 layer->layer_type = layerType;
1150
1151 layer->properties.push_back( PROPERTY() );
1152 PROPERTY* property = &layer->properties.back();
1153 property->name = "index";
1154 property->value = std::to_string( pcbNdx );
1155 }
1156 }
1157
1158 // a space in a quoted token is NOT a terminator, true establishes this.
1159 m_pcb->m_parser->space_in_quoted_tokens = true;
1160
1161 //-----<unit_descriptor> & <resolution_descriptor>--------------------
1162 {
1163 // Tell freerouter to use "tenths of micrometers", which is 100 nm resolution. Possibly
1164 // more resolution is possible in freerouter, but it would need testing.
1165
1166 m_pcb->m_unit->units = T_um;
1167 m_pcb->m_resolution->units = T_um;
1168 m_pcb->m_resolution->value = 10; // tenths of a um
1169 }
1170
1171 //-----<boundary_descriptor>------------------------------------------
1172 {
1173 // Because fillBOUNDARY() can throw an exception, we link in an empty boundary so the
1174 // BOUNDARY does not get lost in the event of of an exception.
1175 BOUNDARY* boundary = new BOUNDARY( nullptr );
1176
1177 m_pcb->m_structure->SetBOUNDARY( boundary );
1178 fillBOUNDARY( aBoard, boundary );
1179 }
1180
1181 //-----<rules>--------------------------------------------------------
1182 {
1183 char rule[80];
1184 int defaultTrackWidth = netSettings->GetDefaultNetclass()->GetTrackWidth();
1185 int defaultClearance = netSettings->GetDefaultNetclass()->GetClearance();
1186 double clearance = scale( defaultClearance );
1187
1188 STRINGS& rules = m_pcb->m_structure->m_rules->m_rules;
1189
1190 std::snprintf( rule, sizeof( rule ), "(width %.6g)", scale( defaultTrackWidth ) );
1191 rules.push_back( rule );
1192
1193 std::snprintf( rule, sizeof( rule ), "(clearance %.6g)", clearance );
1194 rules.push_back( rule );
1195
1196 // Pad to pad spacing on a single SMT part can be closer than our clearance. We don't want
1197 // freerouter complaining about that, so output a significantly smaller pad to pad
1198 // clearance to freerouter.
1199 clearance = scale( defaultClearance ) / 4;
1200
1201 std::snprintf( rule, sizeof( rule ), "(clearance %.6g (type smd_smd))", clearance );
1202 rules.push_back( rule );
1203 }
1204
1205 //-----<zones (not keepout areas) become planes>--------------------------------
1206 // Note: only zones are output here, keepout areas are created later.
1207 {
1208 int netlessZones = 0;
1209
1210 for( ZONE* zone : aBoard->Zones() )
1211 {
1212 if( zone->GetIsRuleArea() )
1213 continue;
1214
1215 // Currently, we export only copper layers
1216 if( ! zone->IsOnCopperLayer() )
1217 continue;
1218
1219 // Now, build zone polygon on each copper layer where the zone
1220 // is living (zones can live on many copper layers)
1221 LSET layerset = zone->GetLayerSet() & LSET::AllCuMask( aBoard->GetCopperLayerCount() );
1222
1223 for( PCB_LAYER_ID layer : layerset )
1224 {
1225 COPPER_PLANE* plane = new COPPER_PLANE( m_pcb->m_structure );
1226
1227 m_pcb->m_structure->m_planes.push_back( plane );
1228
1229 PATH* mainPolygon = new PATH( plane, T_polygon );
1230
1231 plane->SetShape( mainPolygon );
1232 plane->m_name = TO_UTF8( zone->GetNetname() );
1233
1234 if( plane->m_name.size() == 0 )
1235 {
1236 // This is one of those no connection zones, netcode=0, and it has no name.
1237 // Create a unique, bogus netname.
1238 NET* no_net = new NET( m_pcb->m_network );
1239
1240
1241 no_net->m_net_id = "@:no_net_" + std::to_string( netlessZones++ );
1242
1243 // add the bogus net name to network->nets.
1244 m_pcb->m_network->m_nets.push_back( no_net );
1245
1246 // use the bogus net name in the netless zone.
1247 plane->m_name = no_net->m_net_id;
1248 }
1249
1250 mainPolygon->layer_id = m_layerIds[ m_kicadLayer2pcb[ layer ] ];
1251
1252 // Handle the main outlines
1253 SHAPE_POLY_SET::ITERATOR iterator;
1254 VECTOR2I startpoint;
1255 bool is_first_point = true;
1256
1257 for( iterator = zone->IterateWithHoles(); iterator; iterator++ )
1258 {
1259 VECTOR2I point( iterator->x, iterator->y );
1260
1261 if( is_first_point )
1262 {
1263 startpoint = point;
1264 is_first_point = false;
1265 }
1266
1267 mainPolygon->AppendPoint( mapPt( point ) );
1268
1269 // this was the end of the main polygon
1270 if( iterator.IsEndContour() )
1271 {
1272 // Close polygon
1273 mainPolygon->AppendPoint( mapPt( startpoint ) );
1274 break;
1275 }
1276 }
1277
1278 WINDOW* window = nullptr;
1279 PATH* cutout = nullptr;
1280
1281 bool isStartContour = true;
1282
1283 // handle the cutouts
1284 for( iterator++; iterator; iterator++ )
1285 {
1286 if( isStartContour )
1287 {
1288 is_first_point = true;
1289 window = new WINDOW( plane );
1290 plane->AddWindow( window );
1291
1292 cutout = new PATH( window, T_polygon );
1293 window->SetShape( cutout );
1294 cutout->layer_id = m_layerIds[ m_kicadLayer2pcb[ layer ] ];
1295 }
1296
1297 // If the point in this iteration is the last of the contour, the next iteration
1298 // will start with a new contour.
1299 isStartContour = iterator.IsEndContour();
1300
1301 wxASSERT( window );
1302 wxASSERT( cutout );
1303
1304 VECTOR2I point( iterator->x, iterator->y );
1305
1306 if( is_first_point )
1307 {
1308 startpoint = point;
1309 is_first_point = false;
1310 }
1311
1312 cutout->AppendPoint( mapPt( point ) );
1313
1314 // Close the polygon
1315 if( iterator.IsEndContour() )
1316 cutout->AppendPoint( mapPt( startpoint ) );
1317 }
1318 } // end build zones by layer
1319 }
1320 }
1321
1322 //-----<zones flagged keepout areas become keepout>--------------------------------
1323 {
1324 for( ZONE* zone : aBoard->Zones() )
1325 {
1326 if( !zone->GetIsRuleArea() )
1327 continue;
1328
1329 // Keepout areas have a type: T_place_keepout, T_via_keepout, T_wire_keepout,
1330 // T_bend_keepout, T_elongate_keepout, T_keepout.
1331 // Pcbnew knows only T_keepout, T_via_keepout and T_wire_keepout
1332 DSN_T keepout_type;
1333
1334 if( zone->GetDoNotAllowVias() && zone->GetDoNotAllowTracks() )
1335 keepout_type = T_keepout;
1336 else if( zone->GetDoNotAllowVias() )
1337 keepout_type = T_via_keepout;
1338 else if( zone->GetDoNotAllowTracks() )
1339 keepout_type = T_wire_keepout;
1340 else
1341 keepout_type = T_keepout;
1342
1343 // Now, build keepout polygon on each copper layer where the zone
1344 // keepout is living (keepout zones can live on many copper layers)
1345 LSET layerset = zone->GetLayerSet() & LSET::AllCuMask( aBoard->GetCopperLayerCount() );
1346
1347 for( PCB_LAYER_ID layer : layerset )
1348 {
1349 KEEPOUT* keepout = new KEEPOUT( m_pcb->m_structure, keepout_type );
1350 m_pcb->m_structure->m_keepouts.push_back( keepout );
1351
1352 PATH* mainPolygon = new PATH( keepout, T_polygon );
1353 keepout->SetShape( mainPolygon );
1354
1355 mainPolygon->layer_id = m_layerIds[ m_kicadLayer2pcb[ layer ] ];
1356
1357 // Handle the main outlines
1358 SHAPE_POLY_SET::ITERATOR iterator;
1359 bool is_first_point = true;
1360 VECTOR2I startpoint;
1361
1362 for( iterator = zone->IterateWithHoles(); iterator; iterator++ )
1363 {
1364 VECTOR2I point( iterator->x, iterator->y );
1365
1366 if( is_first_point )
1367 {
1368 startpoint = point;
1369 is_first_point = false;
1370 }
1371
1372 mainPolygon->AppendPoint( mapPt( point ) );
1373
1374 // this was the end of the main polygon
1375 if( iterator.IsEndContour() )
1376 {
1377 mainPolygon->AppendPoint( mapPt( startpoint ) );
1378 break;
1379 }
1380 }
1381
1382 WINDOW* window = nullptr;
1383 PATH* cutout = nullptr;
1384
1385 bool isStartContour = true;
1386
1387 // handle the cutouts
1388 for( iterator++; iterator; iterator++ )
1389 {
1390 if( isStartContour )
1391 {
1392 is_first_point = true;
1393 window = new WINDOW( keepout );
1394 keepout->AddWindow( window );
1395
1396 cutout = new PATH( window, T_polygon );
1397 window->SetShape( cutout );
1398 cutout->layer_id = m_layerIds[ m_kicadLayer2pcb[ layer ] ];
1399 }
1400
1401 isStartContour = iterator.IsEndContour();
1402
1403 wxASSERT( window );
1404 wxASSERT( cutout );
1405
1406 VECTOR2I point( iterator->x, iterator->y );
1407
1408 if( is_first_point )
1409 {
1410 startpoint = point;
1411 is_first_point = false;
1412 }
1413
1414 cutout->AppendPoint( mapPt(point) );
1415
1416 // Close the polygon
1417 if( iterator.IsEndContour() )
1418 cutout->AppendPoint( mapPt( startpoint ) );
1419 }
1420 }
1421 }
1422 }
1423
1424 //-----<build the images, components, and netlist>-----------------------
1425 {
1426 PIN_REF empty( m_pcb->m_network );
1427 std::string componentId;
1428 int highestNetCode = 0;
1429 const NETINFO_LIST& netInfo = aBoard->GetNetInfo();
1430
1431 // find the highest numbered netCode within the board.
1432 for( NETINFO_LIST::iterator i = netInfo.begin(); i != netInfo.end(); ++i )
1433 highestNetCode = std::max( highestNetCode, i->GetNetCode() );
1434
1435 deleteNETs();
1436
1437 // expand the net vector to highestNetCode+1, setting empty to NULL
1438 m_nets.resize( highestNetCode + 1, nullptr );
1439
1440 for( unsigned i = 1 /* skip "No Net" at [0] */; i < m_nets.size(); ++i )
1441 m_nets[i] = new NET( m_pcb->m_network );
1442
1443 for( NETINFO_LIST::iterator i = netInfo.begin(); i != netInfo.end(); ++i )
1444 {
1445 if( i->GetNetCode() > 0 )
1446 m_nets[i->GetNetCode()]->m_net_id = TO_UTF8( i->GetNetname() );
1447 }
1448
1449 m_padstackset.clear();
1450
1451 for( FOOTPRINT* footprint : aBoard->Footprints() )
1452 {
1453 IMAGE* image = makeIMAGE( aBoard, footprint );
1454
1455 componentId = TO_UTF8( footprint->GetReference() );
1456
1457 // Create a net list entry for all the actual pins in the current footprint.
1458 // Location of this code is critical because we fabricated some pin names to ensure
1459 // unique-ness within a footprint, and the life of this 'IMAGE* image' is not
1460 // necessarily long. The exported netlist will have some fabricated pin names in it.
1461 // If you don't like fabricated pin names, then make sure all pads within your
1462 // FOOTPRINTs are uniquely named!
1463 for( unsigned p = 0; p < image->m_pins.size(); ++p )
1464 {
1465 PIN* pin = &image->m_pins[p];
1466 int netcode = pin->m_kiNetCode;
1467
1468 if( netcode > 0 )
1469 {
1470 NET* net = m_nets[netcode];
1471
1472 net->m_pins.push_back( empty );
1473
1474 PIN_REF& pin_ref = net->m_pins.back();
1475
1476 pin_ref.component_id = componentId;
1477 pin_ref.pin_id = pin->m_pin_id;
1478 }
1479 }
1480
1481 IMAGE* registered = m_pcb->m_library->LookupIMAGE( image );
1482
1483 if( registered != image )
1484 {
1485 // If our new 'image' is not a unique IMAGE, delete it.
1486 // and use the registered one, known as 'image' after this.
1487 delete image;
1488 image = registered;
1489 }
1490
1491 COMPONENT* comp = m_pcb->m_placement->LookupCOMPONENT( image->GetImageId() );
1492 PLACE* place = new PLACE( comp );
1493
1494 comp->m_places.push_back( place );
1495
1496 place->SetRotation( footprint->GetOrientationDegrees() );
1497 place->SetVertex( mapPt( footprint->GetPosition() ) );
1498 place->m_component_id = componentId;
1499 place->m_part_number = TO_UTF8( footprint->GetValue() );
1500
1501 // footprint is flipped from bottom side, set side to T_back
1502 if( footprint->GetFlag() )
1503 {
1504 EDA_ANGLE angle = ANGLE_180 - footprint->GetOrientation();
1505 place->SetRotation( angle.Normalize().AsDegrees() );
1506
1507 place->m_side = T_back;
1508 }
1509 }
1510
1511 // copy the SPECCTRA_DB::padstackset to the LIBRARY. Since we are
1512 // removing, do not increment the iterator
1513 for( PADSTACKSET::iterator i = m_padstackset.begin(); i != m_padstackset.end();
1514 i = m_padstackset.begin() )
1515 {
1516 PADSTACKSET::auto_type ps = m_padstackset.release( i );
1517 PADSTACK* padstack = ps.release();
1518
1519 m_pcb->m_library->AddPadstack( padstack );
1520 }
1521
1522 // copy our SPECCTRA_DB::nets to the pcb->network
1523 for( unsigned n = 1; n < m_nets.size(); ++n )
1524 {
1525 NET* net = m_nets[n];
1526
1527 if( net->m_pins.size() )
1528 {
1529 // give ownership to pcb->network
1530 m_pcb->m_network->m_nets.push_back( net );
1531 m_nets[n] = nullptr;
1532 }
1533 }
1534 }
1535
1536 // Create a list of all in-use non-default netclasses
1537 std::unordered_map<wxString, NETCLASS*> netclassesInUse;
1538
1539 for( NETINFO_ITEM* net : aBoard->GetNetInfo() )
1540 {
1541 NETCLASS* netclass = net->GetNetClass();
1542 const wxString& name = netclass->GetName();
1543
1544 // Don't add the default netclass
1545 if( name == NETCLASS::Default )
1546 continue;
1547
1548 if( !netclassesInUse.contains( name ) )
1549 netclassesInUse[name] = netclass;
1550 }
1551
1552 //-----< output vias used in netclasses >-----------------------------------
1553 {
1554 // Assume the netclass vias are all the same kind of thru, blind, or buried vias.
1555 // This is in lieu of either having each netclass via have its own layer pair in
1556 // the netclass dialog, or such control in the specctra export dialog.
1557
1558 m_top_via_layer = 0; // first specctra cu layer is number zero.
1560
1561 // Add the via from the Default netclass first. The via container
1562 // in pcb->library preserves the sequence of addition.
1563
1564 PADSTACK* via = makeVia( netSettings->GetDefaultNetclass()->GetViaDiameter(),
1565 netSettings->GetDefaultNetclass()->GetViaDrill(), m_top_via_layer,
1567
1568 // we AppendVia() this first one, there is no way it can be a duplicate,
1569 // the pcb->library via container is empty at this point. After this,
1570 // we'll have to use LookupVia().
1571 wxASSERT( m_pcb->m_library->m_vias.size() == 0 );
1572 m_pcb->m_library->AppendVia( via );
1573
1574 // set the "spare via" index at the start of the
1575 // pcb->library->spareViaIndex = pcb->library->vias.size();
1576
1577 // output the non-Default netclass vias
1578 for( const auto& [name, netclass] : netclassesInUse )
1579 {
1580 via = makeVia( netclass->GetViaDiameter(), netclass->GetViaDrill(),
1582
1583 // maybe add 'via' to the library, but only if unique.
1584 PADSTACK* registered = m_pcb->m_library->LookupVia( via );
1585
1586 if( registered != via )
1587 delete via;
1588 }
1589 }
1590
1591 //-----<create the wires from tracks>-----------------------------------
1592 {
1593 // export all of them for now, later we'll decide what controls we need on this.
1594 std::string netname;
1595 WIRING* wiring = m_pcb->m_wiring;
1596 PATH* path = nullptr;
1597
1598 int old_netcode = -1;
1599 int old_width = -1;
1600 int old_layer = UNDEFINED_LAYER;
1601
1602 for( PCB_TRACK* track : aBoard->Tracks() )
1603 {
1604 if( !track->IsType( { PCB_TRACE_T, PCB_ARC_T } ) )
1605 continue;
1606
1607 int netcode = track->GetNetCode();
1608
1609 if( netcode == 0 )
1610 continue;
1611
1612 if( old_netcode != netcode
1613 || old_width != track->GetWidth()
1614 || old_layer != track->GetLayer()
1615 || ( path && path->points.back() != mapPt( track->GetStart() ) ) )
1616 {
1617 old_width = track->GetWidth();
1618 old_layer = track->GetLayer();
1619
1620 if( old_netcode != netcode )
1621 {
1622 old_netcode = netcode;
1623 NETINFO_ITEM* net = aBoard->FindNet( netcode );
1624 wxASSERT( net );
1625 netname = TO_UTF8( net->GetNetname() );
1626 }
1627
1628 WIRE* wire = new WIRE( wiring );
1629
1630 wiring->wires.push_back( wire );
1631 wire->m_net_id = netname;
1632
1633 if( track->IsLocked() )
1634 wire->m_wire_type = T_fix; // tracks with fix property are not returned in .ses files
1635 else
1636 wire->m_wire_type = T_route; // could be T_protect
1637
1638 PCB_LAYER_ID kiLayer = track->GetLayer();
1639 int pcbLayer = m_kicadLayer2pcb[kiLayer];
1640
1641 path = new PATH( wire );
1642 wire->SetShape( path );
1643 path->layer_id = m_layerIds[pcbLayer];
1644 path->aperture_width = scale( old_width );
1645 path->AppendPoint( mapPt( track->GetStart() ) );
1646 }
1647
1648 if( path ) // Should not occur
1649 path->AppendPoint( mapPt( track->GetEnd() ) );
1650 }
1651 }
1652
1653 //-----<export the existing real BOARD instantiated vias>-----------------
1654 {
1655 // Export all vias, once per unique size and drill diameter combo.
1656 for( PCB_TRACK* track : aBoard->Tracks() )
1657 {
1658 if( track->Type() != PCB_VIA_T )
1659 continue;
1660
1661 PCB_VIA* via = static_cast<PCB_VIA*>( track );
1662 int netcode = via->GetNetCode();
1663
1664 if( netcode == 0 )
1665 continue;
1666
1667 PADSTACK* padstack = makeVia( via );
1668 PADSTACK* registered = m_pcb->m_library->LookupVia( padstack );
1669
1670 // if the one looked up is not our padstack, then delete our padstack
1671 // since it was a duplicate of one already registered.
1672 if( padstack != registered )
1673 delete padstack;
1674
1675 WIRE_VIA* dsnVia = new WIRE_VIA( m_pcb->m_wiring );
1676
1677 m_pcb->m_wiring->wire_vias.push_back( dsnVia );
1678
1679 dsnVia->m_padstack_id = registered->m_padstack_id;
1680 dsnVia->m_vertexes.push_back( mapPt( via->GetPosition() ) );
1681
1682 NETINFO_ITEM* net = aBoard->FindNet( netcode );
1683 wxASSERT( net );
1684
1685 dsnVia->m_net_id = TO_UTF8( net->GetNetname() );
1686
1687 if( via->IsLocked() )
1688 dsnVia->m_via_type = T_fix; // vias with fix property are not returned in .ses files
1689 else
1690 dsnVia->m_via_type = T_route; // could be T_protect
1691 }
1692 }
1693
1694 //-----<via_descriptor>-------------------------------------------------
1695 {
1696 // The pcb->library will output <padstack_descriptors> which is a combined list of part
1697 // padstacks and via padstacks. specctra dsn uses the <via_descriptors> to say which of
1698 // those padstacks are vias.
1699
1700 // Output the vias in the padstack list here, by name only. This must be done after
1701 // exporting existing vias as WIRE_VIAs.
1702 VIA* vias = m_pcb->m_structure->m_via;
1703
1704 for( unsigned viaNdx = 0; viaNdx < m_pcb->m_library->m_vias.size(); ++viaNdx )
1705 vias->AppendVia( m_pcb->m_library->m_vias[viaNdx].m_padstack_id.c_str() );
1706 }
1707
1708 //-----<output NETCLASSs>----------------------------------------------------
1709
1710 // Export netclass info
1711 exportNETCLASS( netSettings->GetDefaultNetclass().get(), aBoard );
1712
1713 for( const auto& [name, netclass] : netclassesInUse )
1714 exportNETCLASS( netclass, aBoard );
1715}
1716
1717
1718void SPECCTRA_DB::exportNETCLASS( const NETCLASS* aNetClass, const BOARD* aBoard )
1719{
1720 /* From page 11 of specctra spec:
1721 *
1722 * Routing and Placement Rule Hierarchies
1723 *
1724 * Routing and placement rules can be defined at multiple levels of design
1725 * specification. When a routing or placement rule is defined for an object at
1726 * multiple levels, a predefined routing or placement precedence order
1727 * automatically determines which rule to apply to the object. The routing rule
1728 * precedence order is
1729 *
1730 * pcb < layer < class < class layer < group_set < group_set layer < net <
1731 * net layer < group < group layer < fromto < fromto layer < class_class <
1732 * class_class layer < padstack < region < class region < net region <
1733 * class_class region
1734 *
1735 * A pcb rule (global rule for the PCB design) has the lowest precedence in the
1736 * hierarchy. A class-to-class region rule has the highest precedence. Rules
1737 * set at one level of the hierarchy override conflicting rules set at lower
1738 * levels. The placement rule precedence order is
1739 *
1740 * pcb < image_set < image < component < super cluster < room <
1741 * room_image_set < family_family < image_image
1742 *
1743 * A pcb rule (global rule for the PCB design) has the lowest precedence in the
1744 * hierarchy. An image-to-image rule has the highest precedence. Rules set at
1745 * one level of the hierarchy override conflicting rules set at lower levels.
1746 */
1747
1748 char text[256];
1749
1750 CLASS* clazz = new CLASS( m_pcb->m_network );
1751
1752 m_pcb->m_network->m_classes.push_back( clazz );
1753
1754 clazz->m_class_id = TO_UTF8( aNetClass->GetName() );
1755
1756 for( NETINFO_ITEM* net : aBoard->GetNetInfo() )
1757 {
1758 if( net->GetNetClass()->GetName() == clazz->m_class_id )
1759 clazz->m_net_ids.push_back( TO_UTF8( net->GetNetname() ) );
1760 }
1761
1762 clazz->m_rules = new RULE( clazz, T_rule );
1763
1764 // output the track width.
1765 int trackWidth = aNetClass->GetTrackWidth();
1766 std::snprintf( text, sizeof( text ), "(width %.6g)", scale( trackWidth ) );
1767 clazz->m_rules->m_rules.push_back( text );
1768
1769 // output the clearance.
1770 int clearance = aNetClass->GetClearance();
1771 std::snprintf( text, sizeof( text ), "(clearance %.6g)", scale( clearance ) );
1772 clazz->m_rules->m_rules.push_back( text );
1773
1774 // Freerouter creates a class named 'default' anyway, and if we try to use that we end up
1775 // with two 'default' via rules so use something else as the name of our default class.
1776 if( aNetClass->GetName() == NETCLASS::Default )
1777 clazz->m_class_id = "kicad_default";
1778
1779 // The easiest way to get the via name is to create a temporary via (which generates the
1780 // name internal to the PADSTACK), and then grab the name and delete the via. There are not
1781 // that many netclasses so this should never become a performance issue.
1782
1783 PADSTACK* via = makeVia( aNetClass->GetViaDiameter(), aNetClass->GetViaDrill(),
1785
1786 snprintf( text, sizeof( text ), "(use_via \"%s\")", via->GetPadstackId().c_str() );
1787 clazz->m_circuit.push_back( text );
1788
1789 delete via;
1790}
1791
1792
1794{
1795 // DSN Images (=KiCad FOOTPRINTs and PADs) must be presented from the top view.
1796 // Note: to export footprints, the footprints must be flipped around the X axis, otherwise
1797 // the rotation angle is not good.
1798 for( FOOTPRINT* footprint : aBoard->Footprints() )
1799 {
1800 footprint->SetFlag( 0 );
1801
1802 if( footprint->GetLayer() == B_Cu )
1803 {
1804 footprint->Flip( footprint->GetPosition(), FLIP_DIRECTION::TOP_BOTTOM );
1805 footprint->SetFlag( 1 );
1806 }
1807 }
1808
1810}
1811
1812
1814{
1816 return;
1817
1818 // DSN Images (=KiCad FOOTPRINTs and PADs) must be presented from the
1819 // top view. Restore those that were flipped.
1820 // Note: to export footprints, the footprints were flipped around the X axis,
1821 for( FOOTPRINT* footprint : aBoard->Footprints() )
1822 {
1823 if( footprint->GetFlag() )
1824 {
1825 footprint->Flip( footprint->GetPosition(), FLIP_DIRECTION::TOP_BOTTOM );
1826 footprint->SetFlag( 0 );
1827 }
1828 }
1829
1830 m_footprintsAreFlipped = false;
1831}
1832
1833} // namespace DSN
const char * name
@ ERROR_INSIDE
constexpr int ARC_HIGH_DEF
Definition base_units.h:129
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
@ LT_POWER
Definition board.h:183
@ LT_MIXED
Definition board.h:184
@ LT_JUMPER
Definition board.h:185
@ LT_SIGNAL
Definition board.h:182
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
Handles how to draw a screen (a board, a schematic ...)
Definition base_screen.h:41
bool IsContentModified() const
Definition base_screen.h:60
void SetContentModified(bool aModified=true)
Definition base_screen.h:59
std::shared_ptr< NET_SETTINGS > m_NetSettings
int GetMaxError() const
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:317
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr, bool aAllowUseArcsInPolygons=false, bool aIncludeNPTHAsOutlines=false)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
Definition board.cpp:2657
const NETINFO_LIST & GetNetInfo() const
Definition board.h:933
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition board.cpp:2152
const ZONES & Zones() const
Definition board.h:362
LAYER_T GetLayerType(PCB_LAYER_ID aLayer) const
Return the type of the copper layer given by aLayer.
Definition board.cpp:746
void SynchronizeNetsAndNetClasses(bool aResetTrackAndViaSizes)
Copy NETCLASS info to each NET, based on NET membership in a NETCLASS.
Definition board.cpp:2287
int GetCopperLayerCount() const
Definition board.cpp:875
const FOOTPRINTS & Footprints() const
Definition board.h:358
const TRACKS & Tracks() const
Definition board.h:356
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1040
constexpr size_type GetWidth() const
Definition box2.h:214
constexpr size_type GetHeight() const
Definition box2.h:215
int GetCount() const
Return the number of objects in the list.
Definition collector.h:83
The <class_descriptor> in the specctra spec.
Definition specctra.h:2753
std::string m_class_id
Definition specctra.h:2828
RULE * m_rules
Definition specctra.h:2835
STRINGS m_net_ids
Definition specctra.h:2830
STRINGS m_circuit
circuit descriptor list
Definition specctra.h:2833
Implement a <component_descriptor> in the specctra dsn spec.
Definition specctra.h:1773
PLACES m_places
Definition specctra.h:1814
A <plane_descriptor> in the specctra dsn spec.
Definition specctra.h:1358
void Append(ELEM *aElem)
Definition specctra.h:327
Used for <keepout_descriptor> and <plane_descriptor>.
Definition specctra.h:911
void AddWindow(WINDOW *aWindow)
Definition specctra.h:952
void SetShape(ELEM *aShape)
Definition specctra.h:935
std::string m_name
Definition specctra.h:1017
PROPERTIES properties
Definition specctra.h:1293
DSN_T layer_type
one of: T_signal, T_power, T_mixed, T_jumper
Definition specctra.h:1284
std::string name
Definition specctra.h:1283
A <net_descriptor> in the DSN spec.
Definition specctra.h:2596
std::string m_net_id
Definition specctra.h:2694
PIN_REFS m_pins
Definition specctra.h:2699
Hold either a via or a pad definition.
Definition specctra.h:2126
std::string m_padstack_id
Definition specctra.h:2225
void SetPadstackId(const char *aPadstackId)
Definition specctra.h:2159
Support both the <path_descriptor> and the <polygon_descriptor> per the specctra dsn spec.
Definition specctra.h:588
void SetLayerId(const std::string &aLayerId)
Definition specctra.h:605
void AppendPoint(const POINT &aPoint)
Definition specctra.h:598
std::string layer_id
Definition specctra.h:655
Implement a <placement_reference> in the specctra dsn spec.
Definition specctra.h:1693
void SetVertex(const POINT &aVertex)
Definition specctra.h:1721
void SetRotation(double aRotation)
Definition specctra.h:1728
DSN_T m_side
Definition specctra.h:1740
std::string m_part_number
Definition specctra.h:1763
std::string m_component_id
reference designator
Definition specctra.h:1738
void SetLayerId(std::string &aLayerId)
Definition specctra.h:452
void SetCorners(const POINT &aPoint0, const POINT &aPoint1)
Definition specctra.h:457
STRINGS m_rules
rules are saved in std::string form.
Definition specctra.h:535
A "(shape ..)" element in the specctra dsn spec.
Definition specctra.h:1899
A DSN data tree, usually coming from a DSN file.
Definition specctra.h:3651
int m_top_via_layer
specctra cu layers, 0 based index:
Definition specctra.h:4016
IMAGE * makeIMAGE(BOARD *aBoard, FOOTPRINT *aFootprint)
Allocates an I#MAGE on the heap and creates all the PINs according to the PADs in the FOOTPRINT.
void buildLayerMaps(BOARD *aBoard)
Create a few data translation structures for layer name and number mapping between the DSN::PCB struc...
Definition specctra.cpp:77
std::map< int, PCB_LAYER_ID > m_pcbLayer2kicad
maps PCB layer number to BOARD layer numbers
Definition specctra.h:4000
void ExportPCB(const wxString &aFilename, bool aNameChange=false)
Write the internal PCB instance out as a SPECTRA DSN format file.
SHAPE_POLY_SET m_brd_outlines
Definition specctra.h:3988
void FlipFOOTPRINTs(BOARD *aBoard)
Flip the footprints which are on the back side of the board to the front.
STRINGS m_layerIds
indexed by PCB layer number
Definition specctra.h:3997
bool m_footprintsAreFlipped
Definition specctra.h:3993
void deleteNETs()
Delete all the NETs that may be in here.
Definition specctra.h:3948
void fillBOUNDARY(BOARD *aBoard, BOUNDARY *aBoundary)
Make the board perimeter for the DSN file by filling the BOUNDARY element in the specctra element tre...
PADSTACK * makePADSTACK(BOARD *aBoard, PAD *aPad)
Create a PADSTACK which matches the given pad.
void SetPCB(PCB *aPcb)
Delete any existing PCB and replaces it with the given one.
Definition specctra.h:3691
static PCB * MakePCB()
Make a PCB with all the default ELEMs and parts on the heap.
bool BuiltBoardOutlines(BOARD *aBoard)
Build the board outlines and store it in m_brd_outlines.
void exportNETCLASS(const NETCLASS *aNetClass, const BOARD *aBoard)
Export aNetClass to the DSN file.
PADSTACK * makeVia(int aCopperDiameter, int aDrillDiameter, int aTopLayer, int aBotLayer)
Make a round through hole PADSTACK using the given KiCad diameter in deci-mils.
std::map< PCB_LAYER_ID, int > m_kicadLayer2pcb
maps BOARD layer number to PCB layer numbers
Definition specctra.h:3999
std::vector< NET * > m_nets
we don't want ownership here permanently, so we don't use boost::ptr_vector
Definition specctra.h:4013
PADSTACKSET m_padstackset
Definition specctra.h:4010
void FromBOARD(BOARD *aBoard)
Add the entire BOARD to the PCB but does not write it out.
void RevertFOOTPRINTs(BOARD *aBoard)
Flip the footprints which were on the back side of the board back to the back.
A <via_descriptor> in the specctra dsn spec.
Definition specctra.h:1044
void AppendVia(const char *aViaName)
Definition specctra.h:1052
void SetShape(ELEM *aShape)
Definition specctra.h:863
A <wire_via_descriptor> in the specctra dsn spec.
Definition specctra.h:2993
std::string m_net_id
Definition specctra.h:3124
std::string m_padstack_id
Definition specctra.h:3122
DSN_T m_via_type
Definition specctra.h:3126
POINTS m_vertexes
Definition specctra.h:3123
A <wire_shape_descriptor> in the specctra dsn spec.
Definition specctra.h:2884
DSN_T m_wire_type
Definition specctra.h:2978
void SetShape(ELEM *aShape)
Definition specctra.h:2904
std::string m_net_id
Definition specctra.h:2976
A <wiring_descriptor> in the specctra dsn spec.
Definition specctra.h:3140
WIRES wires
Definition specctra.h:3177
EDA_ANGLE Normalize()
Definition eda_angle.h:229
double AsDegrees() const
Definition eda_angle.h:116
EDA_ANGLE GetArcAngle() const
int GetRadius() const
SHAPE_T GetShape() const
Definition eda_shape.h:168
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:215
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:173
EDA_ANGLE GetOrientation() const
Definition footprint.h:248
ZONES & Zones()
Definition footprint.h:230
const LIB_ID & GetFPID() const
Definition footprint.h:269
VECTOR2I GetPosition() const override
Definition footprint.h:245
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
UTF8 Format() const
Definition lib_id.cpp:119
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:41
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
LSEQ CuStack() const
Return a sequence of copper layers in starting from the front/top and extending to the back/bottom.
Definition lset.cpp:246
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:582
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:591
A collection of nets and the parameters used to route or test these nets.
Definition netclass.h:45
int GetViaDiameter() const
Definition netclass.h:133
int GetViaDrill() const
Definition netclass.h:141
static const char Default[]
the name of the default NETCLASS
Definition netclass.h:47
const wxString GetName() const
Gets the name of this (maybe aggregate) netclass in a format for internal usage or for export to exte...
Definition netclass.cpp:322
int GetTrackWidth() const
Definition netclass.h:125
int GetClearance() const
Definition netclass.h:117
Handle the data for a net.
Definition netinfo.h:54
const wxString & GetNetname() const
Definition netinfo.h:112
Wrapper class, so you can iterate through NETINFO_ITEM*s, not std::pair<int/wxString,...
Definition netinfo.h:391
Container for NETINFO_ITEM elements, which are the nets.
Definition netinfo.h:330
iterator begin() const
Definition netinfo.h:436
iterator end() const
Definition netinfo.h:441
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:145
Definition pad.h:54
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition pad.h:437
void MergePrimitivesAsPolygon(PCB_LAYER_ID aLayer, SHAPE_POLY_SET *aMergedPolygon, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Merge all basic shapes to a SHAPE_POLY_SET.
Definition pad.cpp:2689
int GetRoundRectCornerRadius(PCB_LAYER_ID aLayer) const
Definition pad.cpp:467
const BOX2I GetBoundingBox() const override
The bounding box is cached, so this will be efficient most of the time.
Definition pad.cpp:867
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition pad.h:783
const VECTOR2I & GetDrillSize() const
Definition pad.h:305
const VECTOR2I & GetDelta(PCB_LAYER_ID aLayer) const
Definition pad.h:299
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition pad.h:195
const VECTOR2I & GetOffset(PCB_LAYER_ID aLayer) const
Definition pad.h:317
int GetChamferPositions(PCB_LAYER_ID aLayer) const
Definition pad.h:711
double GetChamferRectRatio(PCB_LAYER_ID aLayer) const
Definition pad.h:694
const VECTOR2I & GetSize(PCB_LAYER_ID aLayer) const
Definition pad.h:264
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
BOARD * GetBoard() const
bool ExportSpecctraFile(const wxString &aFullFilename)
Export the current BOARD to a specctra dsn file.
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition pcb_shape.h:81
int GetWidth() const override
Collect all BOARD_ITEM objects of a given set of KICAD_T type(s).
Definition collectors.h:521
void Collect(BOARD_ITEM *aBoard, const std::vector< KICAD_T > &aTypes)
Collect BOARD_ITEM objects using this class's Inspector method, which does the collection.
int GetWidth() const override
int GetDrillValue() const
Calculate the drill value for vias (m_drill if > 0, or default drill value for the board).
void LayerPair(PCB_LAYER_ID *top_layer, PCB_LAYER_ID *bottom_layer) const
Return the 2 layers used by the via (the via actually uses all layers between these 2 layers)
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int PointCount() const
Return the number of points (vertices) in this line chain.
void Clear()
Remove all points from the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
Represent a set of closed polygons.
HASH_128 GetHash() const
ITERATOR_TEMPLATE< VECTOR2I > ITERATOR
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
const char * c_str() const
Definition utf8.h:109
Handle a list of polygons defining a copper zone.
Definition zone.h:74
SHAPE_POLY_SET::ITERATOR IterateWithHoles()
Return an iterator to visit all points of the zone's main outline with holes.
Definition zone.h:539
void Rotate(const VECTOR2I &aCentre, const EDA_ANGLE &aAngle) override
Rotate the outlines.
Definition zone.cpp:1031
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:194
This file is part of the common library.
int ConvertArcToPolyline(SHAPE_LINE_CHAIN &aPolyline, VECTOR2I aCenter, int aRadius, const EDA_ANGLE &aStartAngleDeg, const EDA_ANGLE &aArcAngleDeg, double aAccuracy, ERROR_LOC aErrorLoc)
Generate a polyline to approximate a arc.
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void TransformRoundChamferedRectToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &aRotation, int aCornerRadius, double aChamferRatio, int aChamferCorners, int aInflate, int aError, ERROR_LOC aErrorLoc)
Convert a rectangle with rounded corners and/or chamfered corners to a polygon.
void BuildConvexHull(std::vector< VECTOR2I > &aResult, const std::vector< VECTOR2I > &aPoly)
Calculate the convex hull of a list of points in counter-clockwise order.
static bool registered
@ PLACE
Definition cursors.h:96
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
#define LAYER(n, l)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:417
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:415
@ SEGMENT
Definition eda_shape.h:45
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:46
a few functions useful in geometry calculations.
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ B_Cu
Definition layer_ids.h:65
@ UNDEFINED_LAYER
Definition layer_ids.h:61
This file contains miscellaneous commonly used macros and functions.
@ TOP_BOTTOM
Flip top to bottom (around the X axis)
Definition mirror.h:29
This source file implements export and import capabilities to the specctra dsn file format.
Definition specctra.cpp:64
std::vector< std::string > STRINGS
Definition specctra.h:171
std::map< wxString, int > PINMAP
data type used to ensure unique-ness of pin names, holding (wxString and int)
static double mapX(int x)
static double mapY(int y)
static double IU2um(int kicadDist)
static POINT mapPt(const VECTOR2I &pt)
Convert a KiCad point into a DSN file point.
static bool isRoundKeepout(PAD *aPad)
Decide if the pad is a copper-less through hole which needs to be made into a round keepout.
std::set< std::string > STRINGSET
static double scale(int kicadDist)
Convert a distance from Pcbnew internal units to the reported Specctra DSN units in floating point fo...
void ExportBoardToSpecctraFile(BOARD *aBoard, const wxString &aFullFilename)
Helper method to export board to DSN file.
static PATH * makePath(const POINT &aStart, const POINT &aEnd, const std::string &aLayerName)
Create a PATH element with a single straight line, a pair of vertices.
std::pair< STRINGSET::iterator, bool > STRINGSET_PAIR
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
@ CHAMFERED_RECT
Definition padstack.h:60
@ ROUNDRECT
Definition padstack.h:57
@ TRAPEZOID
Definition padstack.h:56
@ RECTANGLE
Definition padstack.h:54
@ NET
This item represents a net.
DSN::T DSN_T
Definition specctra.h:54
const int scale
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
A <pin_reference> definition in the specctra dsn spec.
Definition specctra.h:2455
std::string pin_id
Definition specctra.h:2481
std::string component_id
Definition specctra.h:2480
A point in the SPECCTRA DSN coordinate system.
Definition specctra.h:108
void FixNegativeZero()
Change negative zero to positive zero in the IEEE floating point storage format.
Definition specctra.h:149
double y
Definition specctra.h:110
double x
Definition specctra.h:109
A storage class for 128-bit hash value.
Definition hash_128.h:36
std::string ToString() const
Definition hash_128.h:47
int radius
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
int clearance
int delta
#define M_PI
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:229
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:88
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:97
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:87
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695