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