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