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