KiCad PCB EDA Suite
import_fabmaster.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) 2020 BeagleBoard Foundation
5 * Copyright (C) 2020-2022 KiCad Developers, see AUTHORS.txt for contributors.
6 * Author: Seth Hillbrand <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 3
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include "import_fabmaster.h"
27
28#include <algorithm>
29#include <array>
30#include <iostream>
31#include <fstream>
32#include <map>
33#include <memory>
34#include <string>
35#include <sstream>
36#include <vector>
37#include <utility>
38
39#include <wx/log.h>
40
41#include <board.h>
43#include <board_item.h>
44#include <footprint.h>
45#include <fp_shape.h>
46#include <pad.h>
47#include <pad_shapes.h>
48#include <pcb_shape.h>
49#include <pcb_text.h>
50#include <pcb_track.h>
51#include <zone.h>
52#include <common.h>
53#include <geometry/shape_arc.h>
54#include <string_utils.h>
55#include <progress_reporter.h>
56#include <math/util.h>
57#include <wx/filename.h>
58
59
61{
62 const unsigned PROGRESS_DELTA = 250;
63
65 {
66 if( ++m_doneCount > m_lastProgressCount + PROGRESS_DELTA )
67 {
69 / std::max( 1U, m_totalCount ) );
70
72 THROW_IO_ERROR( _( "Open cancelled by user." ) );
73
75 }
76 }
77}
78
79
80double FABMASTER::readDouble( const std::string& aStr ) const
81{
82 std::istringstream istr( aStr );
83 istr.imbue( std::locale::classic() );
84
85 double doubleValue;
86 istr >> doubleValue;
87 return doubleValue;
88}
89
90
91int FABMASTER::readInt( const std::string& aStr ) const
92{
93 std::istringstream istr( aStr );
94 istr.imbue( std::locale::classic() );
95
96 int intValue;
97 istr >> intValue;
98 return intValue;
99}
100
101
102bool FABMASTER::Read( const std::string& aFile )
103{
104
105 std::ifstream ifs( aFile, std::ios::in | std::ios::binary );
106
107 if( !ifs.is_open() )
108 return false;
109
110 m_filename = aFile;
111
112 // Read/ignore all bytes in the file to find the size and then go back to the beginning
113 ifs.ignore( std::numeric_limits<std::streamsize>::max() );
114 std::streamsize length = ifs.gcount();
115 ifs.clear();
116 ifs.seekg( 0, std::ios_base::beg );
117
118 std::string buffer( std::istreambuf_iterator<char>{ ifs }, {} );
119
120 std::vector < std::string > row;
121
122 // Reserve an estimate of the number of rows to prevent continual re-allocation
123 // crashing (Looking at you MSVC)
124 row.reserve( length / 100 );
125 std::string cell;
126 cell.reserve( 100 );
127
128 bool quoted = false;
129
130 for( auto& ch : buffer )
131 {
132 switch( ch )
133 {
134 case '"':
135
136 if( cell.empty() || cell[0] == '"' )
137 quoted = !quoted;
138
139 cell += ch;
140 break;
141
142 case '!':
143 if( !quoted )
144 {
145 row.push_back( cell );
146 cell.clear();
147 }
148 else
149 cell += ch;
150
151 break;
152
153 case '\n':
154
156 if( !cell.empty() )
157 row.push_back( cell );
158
159 cell.clear();
160 rows.push_back( row );
161 row.clear();
162 quoted = false;
163 break;
164
165 case '\r':
166 break;
167
168 default:
169 cell += std::toupper( ch );
170 }
171 }
172
173 // Handle last line without linebreak
174 if( !cell.empty() || !row.empty() )
175 {
176 row.push_back( cell );
177 cell.clear();
178 rows.push_back( row );
179 row.clear();
180 }
181
182 return true;
183}
184
186{
187 single_row row;
188 try
189 {
190 row = rows.at( aOffset );
191 }
192 catch( std::out_of_range& )
193 {
194 return UNKNOWN_EXTRACT;
195 }
196
197 if( row.size() < 3 )
198 return UNKNOWN_EXTRACT;
199
200 if( row[0].back() != 'A' )
201 return UNKNOWN_EXTRACT;
202
203 std::string row1 = row[1];
204 std::string row2 = row[2];
205 std::string row3{};
206
208 alg::delete_if( row1, []( char c ){ return c == '_'; } );
209 alg::delete_if( row2, []( char c ){ return c == '_'; } );
210
211 if( row.size() > 3 )
212 {
213 row3 = row[3];
214 alg::delete_if( row3, []( char c ){ return c == '_'; } );
215 }
216
217 if( row1 == "REFDES" && row2 == "COMPCLASS" )
218 return EXTRACT_REFDES;
219
220 if( row1 == "NETNAME" && row2 == "REFDES" )
221 return EXTRACT_NETS;
222
223 if( row1 == "CLASS" && row2 == "SUBCLASS" && row3.empty() )
225
226 if( row1 == "GRAPHICDATANAME" && row2 == "GRAPHICDATANUMBER" )
227 return EXTRACT_GRAPHICS;
228
229 if( row1 == "CLASS" && row2 == "SUBCLASS" && row3 == "GRAPHICDATANAME" )
230 return EXTRACT_TRACES;
231
232 if( row1 == "SYMNAME" && row2 == "PINNAME" )
234
235 if( row1 == "SYMNAME" && row2 == "SYMMIRROR" && row3 == "PINNAME" )
236 return EXTRACT_PINS;
237
238 if( row1 == "VIAX" && row2 == "VIAY" )
239 return EXTRACT_VIAS;
240
241 if( row1 == "SUBCLASS" && row2 == "PADSHAPENAME" )
242 return EXTRACT_PAD_SHAPES;
243
244 if( row1 == "PADNAME" )
245 return EXTRACT_PADSTACKS;
246
247 if( row1 == "LAYERSORT" )
248 return EXTRACT_FULL_LAYERS;
249
250 wxLogError( _( "Unknown FABMASTER section %s:%s at row %zu." ),
251 row1.c_str(),
252 row2.c_str(),
253 aOffset );
254 return UNKNOWN_EXTRACT;
255
256}
257
258double FABMASTER::processScaleFactor( size_t aRow )
259{
260 double retval = 0.0;
261
262 if( aRow >= rows.size() )
263 return -1.0;
264
265 if( rows[aRow].size() < 11 )
266 {
267 wxLogError( _( "Invalid row size in J row %zu. Expecting 11 elements but found %zu." ),
268 aRow,
269 rows[aRow].size() );
270 return -1.0;
271 }
272
273 for( int i = 7; i < 10 && retval < 1.0; ++i )
274 {
275 std::string units = rows[aRow][i];
276 std::transform(units.begin(), units.end(),units.begin(), ::toupper);
277
278 if( units == "MILS" )
279 retval = pcbIUScale.IU_PER_MILS;
280 else if( units == "MILLIMETERS" )
281 retval = pcbIUScale.IU_PER_MM;
282 else if( units == "MICRONS" )
283 retval = pcbIUScale.IU_PER_MM * 10.0;
284 else if( units == "INCHES" )
285 retval = pcbIUScale.IU_PER_MILS * 1000.0;
286 }
287
288 if( retval < 1.0 )
289 {
290 wxLogError( _( "Could not find units value, defaulting to mils." ) );
291 retval = pcbIUScale.IU_PER_MILS;
292 }
293
294 return retval;
295}
296
297int FABMASTER::getColFromName( size_t aRow, const std::string& aStr )
298{
299 if( aRow >= rows.size() )
300 return -1;
301
302 std::vector<std::string> header = rows[aRow];
303
304 for( size_t i = 0; i < header.size(); i++ )
305 {
308 alg::delete_if( header[i], []( const char c ) { return c == '_'; } );
309
310 if( header[i] == aStr )
311 return i;
312 }
313
314 THROW_IO_ERROR( wxString::Format( _( "Could not find column label %s." ), aStr.c_str() ) );
315 return -1;
316}
317
318
319PCB_LAYER_ID FABMASTER::getLayer( const std::string& aLayerName )
320{
321 const auto& kicad_layer = layers.find( aLayerName);
322
323 if( kicad_layer == layers.end() )
324 return UNDEFINED_LAYER;
325 else
326 return static_cast<PCB_LAYER_ID>( kicad_layer->second.layerid );
327}
328
329
331{
332 size_t rownum = aRow + 2;
333
334 if( rownum >= rows.size() )
335 return -1;
336
337 const single_row& header = rows[aRow];
338
339 int pad_name_col = getColFromName( aRow, "PADNAME" );
340 int pad_num_col = getColFromName( aRow, "RECNUMBER" );
341 int pad_lay_col = getColFromName( aRow, "LAYER" );
342 int pad_fix_col = getColFromName( aRow, "FIXFLAG" );
343 int pad_via_col = getColFromName( aRow, "VIAFLAG" );
344 int pad_shape_col = getColFromName( aRow, "PADSHAPE1" );
345 int pad_width_col = getColFromName( aRow, "PADWIDTH" );
346 int pad_height_col = getColFromName( aRow, "PADHGHT" );
347 int pad_xoff_col = getColFromName( aRow, "PADXOFF" );
348 int pad_yoff_col = getColFromName( aRow, "PADYOFF" );
349 int pad_flash_col = getColFromName( aRow, "PADFLASH" );
350 int pad_shape_name_col = getColFromName( aRow, "PADSHAPENAME" );
351
352 for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
353 {
354 const single_row& row = rows[rownum];
355
356 if( row.size() != header.size() )
357 {
358 wxLogError( _( "Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
359 rownum,
360 header.size(),
361 row.size() );
362 continue;
363 }
364
365 auto pad_name = row[pad_name_col];
366 auto pad_num = row[pad_num_col];
367 auto pad_layer = row[pad_lay_col];
368 auto pad_is_fixed = row[pad_fix_col];
369 auto pad_is_via = row[pad_via_col];
370 auto pad_shape = row[pad_shape_col];
371 auto pad_width = row[pad_width_col];
372 auto pad_height = row[pad_height_col];
373 auto pad_xoff = row[pad_xoff_col];
374 auto pad_yoff = row[pad_yoff_col];
375 auto pad_flash = row[pad_flash_col];
376 auto pad_shapename = row[pad_shape_name_col];
377
378 // This layer setting seems to be unused
379 if( pad_layer == "INTERNAL_PAD_DEF" || pad_layer == "internal_pad_def" )
380 continue;
381
382 // Skip the technical layers
383 if( pad_layer[0] == '~' )
384 break;
385
386 auto result = layers.emplace( pad_layer, FABMASTER_LAYER{} );
387 FABMASTER_LAYER& layer = result.first->second;
388
390 if( layer.id == 0 )
391 {
392 layer.name = pad_layer;
393 layer.id = readInt( pad_num );
394 layer.conductive = true;
395 }
396 }
397
398 return 0;
399}
400
401
408size_t FABMASTER::processPadStacks( size_t aRow )
409{
410 size_t rownum = aRow + 2;
411
412 if( rownum >= rows.size() )
413 return -1;
414
415 const single_row& header = rows[aRow];
416 double scale_factor = processScaleFactor( aRow + 1 );
417
418 if( scale_factor <= 0.0 )
419 return -1;
420
421 int pad_name_col = getColFromName( aRow, "PADNAME" );
422 int pad_num_col = getColFromName( aRow, "RECNUMBER" );
423 int pad_lay_col = getColFromName( aRow, "LAYER" );
424 int pad_fix_col = getColFromName( aRow, "FIXFLAG" );
425 int pad_via_col = getColFromName( aRow, "VIAFLAG" );
426 int pad_shape_col = getColFromName( aRow, "PADSHAPE1" );
427 int pad_width_col = getColFromName( aRow, "PADWIDTH" );
428 int pad_height_col = getColFromName( aRow, "PADHGHT" );
429 int pad_xoff_col = getColFromName( aRow, "PADXOFF" );
430 int pad_yoff_col = getColFromName( aRow, "PADYOFF" );
431 int pad_flash_col = getColFromName( aRow, "PADFLASH" );
432 int pad_shape_name_col = getColFromName( aRow, "PADSHAPENAME" );
433
434 for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
435 {
436 const single_row& row = rows[rownum];
437 FM_PAD* pad;
438
439 if( row.size() != header.size() )
440 {
441 wxLogError( _( "Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
442 rownum,
443 header.size(),
444 row.size() );
445 continue;
446 }
447
448 auto pad_name = row[pad_name_col];
449 auto pad_num = row[pad_num_col];
450 auto pad_layer = row[pad_lay_col];
451 auto pad_is_fixed = row[pad_fix_col];
452 auto pad_is_via = row[pad_via_col];
453 auto pad_shape = row[pad_shape_col];
454 auto pad_width = row[pad_width_col];
455 auto pad_height = row[pad_height_col];
456 auto pad_xoff = row[pad_xoff_col];
457 auto pad_yoff = row[pad_yoff_col];
458 auto pad_flash = row[pad_flash_col];
459 auto pad_shapename = row[pad_shape_name_col];
460
461 // This layer setting seems to be unused
462 if( pad_layer == "INTERNAL_PAD_DEF" || pad_layer == "internal_pad_def" )
463 continue;
464
465 int recnum = KiROUND( readDouble( pad_num ) );
466
467 auto new_pad = pads.find( pad_name );
468
469 if( new_pad != pads.end() )
470 pad = &new_pad->second;
471 else
472 {
473 pads[pad_name] = FM_PAD();
474 pad = &pads[pad_name];
475 pad->name = pad_name;
476 }
477
479 if( pad_layer == "~DRILL" )
480 {
481 int drill_hit;
482 int drill_x;
483 int drill_y;
484
485 try
486 {
487 drill_hit = KiROUND( std::fabs( readDouble( pad_shape ) * scale_factor ) );
488 drill_x = KiROUND( std::fabs( readDouble( pad_width ) * scale_factor ) );
489 drill_y = KiROUND( std::fabs( readDouble( pad_height ) * scale_factor ) );
490 }
491 catch( ... )
492 {
493 wxLogError( _( "Expecting drill size value but found %s!%s!%s in row %zu." ),
494 pad_shape.c_str(),
495 pad_width.c_str(),
496 pad_height.c_str(),
497 rownum );
498 continue;
499 }
500
501 if( drill_hit == 0 )
502 {
503 pad->drill = false;
504 continue;
505 }
506
507 pad->drill = true;
508
511 if( drill_x == drill_y )
512 {
513 pad->drill_size_x = drill_hit;
514 pad->drill_size_y = drill_hit;
515 }
516 else
517 {
518 pad->drill_size_x = drill_x;
519 pad->drill_size_y = drill_y;
520 }
521
522 if( !pad_shapename.empty() && pad_shapename[0] == 'P' )
523 pad->plated = true;
524
525 continue;
526 }
527
528 if( pad_shape.empty() )
529 continue;
530
531 double w;
532 double h;
533
534 try
535 {
536 w = readDouble( pad_width ) * scale_factor;
537 h = readDouble( pad_height ) * scale_factor;
538 }
539 catch( ... )
540 {
541 wxLogError( _( "Expecting pad size values but found %s : %s in row %zu." ),
542 pad_width.c_str(),
543 pad_height.c_str(),
544 rownum );
545 continue;
546 }
547
548 if( w <= 0.0 )
549 continue;
550
551 auto layer = layers.find( pad_layer );
552
553 if( layer != layers.end() )
554 {
555 if( layer->second.layerid == F_Cu )
556 pad->top = true;
557 else if( layer->second.layerid == B_Cu )
558 pad->bottom = true;
559 }
560
561 if( w > std::numeric_limits<int>::max() || h > std::numeric_limits<int>::max() )
562 {
563 wxLogError( _( "Invalid pad size in row %zu." ), rownum );
564 continue;
565 }
566
567 if( pad_layer == "~TSM" || pad_layer == "~BSM" )
568 {
569 if( w > 0.0 && h > 0.0 )
570 {
571 pad->mask_width = KiROUND( w );
572 pad->mask_height = KiROUND( h );
573 }
574 continue;
575 }
576
577 if( pad_layer == "~TSP" || pad_layer == "~BSP" )
578 {
579 if( w > 0.0 && h > 0.0 )
580 {
581 pad->paste_width = KiROUND( w );
582 pad->paste_height = KiROUND( h );
583 }
584 continue;
585 }
586
588 if( pad_layer[0] == '~' )
589 continue;
590
591 try
592 {
593 pad->x_offset = KiROUND( readDouble( pad_xoff ) * scale_factor );
594 pad->y_offset = -KiROUND( readDouble( pad_yoff ) * scale_factor );
595 }
596 catch( ... )
597 {
598 wxLogError( _( "Expecting pad offset values but found %s:%s in row %zu." ),
599 pad_xoff.c_str(),
600 pad_yoff.c_str(),
601 rownum );
602 continue;
603 }
604
605 if( w > 0.0 && h > 0.0 && recnum == 1 )
606 {
607 pad->width = KiROUND( w );
608 pad->height = KiROUND( h );
609 pad->via = ( std::toupper( pad_is_via[0] ) != 'V' );
610
611 if( pad_shape == "CIRCLE" )
612 {
613 pad->height = pad->width;
614 pad->shape = PAD_SHAPE::CIRCLE;
615 }
616 else if( pad_shape == "RECTANGLE" )
617 {
618 pad->shape = PAD_SHAPE::RECT;
619 }
620 else if( pad_shape == "ROUNDED_RECT" )
621 {
622 pad->shape = PAD_SHAPE::ROUNDRECT;
623 }
624 else if( pad_shape == "SQUARE" )
625 {
626 pad->shape = PAD_SHAPE::RECT;
627 pad->height = pad->width;
628 }
629 else if( pad_shape == "OBLONG" || pad_shape == "OBLONG_X" || pad_shape == "OBLONG_Y" )
630 pad->shape = PAD_SHAPE::OVAL;
631 else if( pad_shape == "OCTAGON" )
632 {
633 pad->shape = PAD_SHAPE::RECT;
634 pad->is_octogon = true;
635 }
636 else if( pad_shape == "SHAPE" )
637 {
638 pad->shape = PAD_SHAPE::CUSTOM;
639 pad->custom_name = pad_shapename;
640 }
641 else
642 {
643 wxLogError( _( "Unknown pad shape name '%s' on layer '%s' in row %zu." ),
644 pad_shape.c_str(),
645 pad_layer.c_str(),
646 rownum );
647 continue;
648 }
649 }
650 }
651
652 return rownum - aRow;
653}
654
655
657{
658 size_t rownum = aRow + 2;
659
660 if( rownum >= rows.size() )
661 return -1;
662
663 auto header = rows[aRow];
664 double scale_factor = processScaleFactor( aRow + 1 );
665
666 if( scale_factor <= 0.0 )
667 return -1;
668
669 int layer_class_col = getColFromName( aRow, "CLASS" );
670 int layer_subclass_col = getColFromName( aRow, "SUBCLASS" );
671
672 if( layer_class_col < 0 || layer_subclass_col < 0 )
673 return -1;
674
675 for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
676 {
677 const single_row& row = rows[rownum];
678
679 if( row.size() != header.size() )
680 {
681 wxLogError( _( "Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
682 rownum,
683 header.size(),
684 row.size() );
685 continue;
686 }
687
688 auto result = layers.emplace( row[layer_subclass_col], FABMASTER_LAYER{} );
689 FABMASTER_LAYER& layer = result.first->second;
690
691 layer.name = row[layer_subclass_col];
692 layer.positive = true;
693 layer.conductive = false;
694
695 if( row[layer_class_col] == "ANTI ETCH" )
696 {
697 layer.positive = false;
698 layer.conductive = true;
699 }
700 else if( row[layer_class_col] == "ETCH" )
701 {
702 layer.conductive = true;
703 }
704 }
705
706 return rownum - aRow;
707}
708
709
711{
712 bool has_l1 = false;
713 int max_layer = 0;
714 std::string max_layer_name;
715
716 std::vector<std::pair<std::string, int>> extra_layers
717 {
718 { "ASSEMBLY_TOP", F_Fab },
719 { "ASSEMBLY_BOTTOM", B_Fab },
720 { "PLACE_BOUND_TOP", F_CrtYd },
721 { "PLACE_BOUND_BOTTOM", B_CrtYd },
722 };
723
724 std::vector<FABMASTER_LAYER*> layer_order;
725
726 for( auto& el : layers )
727 {
728 FABMASTER_LAYER& layer = el.second;
730
731 if( layer.conductive )
732 {
733 layer_order.push_back( &layer );
734 }
735 else if( layer.name.find( "SILK" ) != std::string::npos &&
736 layer.name.find( "AUTOSILK" ) == std::string::npos ) // Skip the autosilk layer
737 {
738 if( layer.name.find( "B" ) != std::string::npos )
739 layer.layerid = B_SilkS;
740 else
741 layer.layerid = F_SilkS;
742 }
743 else if( layer.name.find( "MASK" ) != std::string::npos ||
744 layer.name.find( "MSK" ) != std::string::npos )
745 {
746 if( layer.name.find( "B" ) != std::string::npos )
747 layer.layerid = B_Mask;
748 else
749 layer.layerid = F_Mask;
750 }
751 else if( layer.name.find( "PAST" ) != std::string::npos )
752 {
753 if( layer.name.find( "B" ) != std::string::npos )
754 layer.layerid = B_Paste;
755 else
756 layer.layerid = F_Paste;
757 }
758 else if( layer.name.find( "NCLEGEND" ) != std::string::npos )
759 layer.layerid = Dwgs_User;
760 else
761 layer.disable = true;
762 }
763
764 std::sort( layer_order.begin(), layer_order.end(), FABMASTER_LAYER::BY_ID() );
765 int layernum = 0;
766
767 for( auto layer : layer_order )
768 layer->layerid = layernum++;
769
772 layer_order.back()->layerid = B_Cu;
773
774 for( auto& new_pair : extra_layers )
775 {
776 FABMASTER_LAYER new_layer;
777
778 new_layer.name = new_pair.first;
779 new_layer.layerid = new_pair.second;
780 new_layer.conductive = false;
781
782 auto result = layers.emplace( new_pair.first, new_layer );
783
784 if( !result.second )
785 {
786 result.first->second.layerid = new_pair.second;
787 result.first->second.disable = false;
788 }
789 }
790
791 return true;
792}
793
794
800size_t FABMASTER::processLayers( size_t aRow )
801{
802 size_t rownum = aRow + 2;
803
804 if( rownum >= rows.size() )
805 return -1;
806
807 auto header = rows[aRow];
808 double scale_factor = processScaleFactor( aRow + 1 );
809
810 if( scale_factor <= 0.0 )
811 return -1;
812
813 int layer_sort_col = getColFromName( aRow, "LAYERSORT" );
814 int layer_subclass_col = getColFromName( aRow, "LAYERSUBCLASS" );
815 int layer_art_col = getColFromName( aRow, "LAYERARTWORK" );
816 int layer_use_col = getColFromName( aRow, "LAYERUSE" );
817 int layer_cond_col = getColFromName( aRow, "LAYERCONDUCTOR" );
818 int layer_er_col = getColFromName( aRow, "LAYERDIELECTRICCONSTANT" );
819 int layer_rho_col = getColFromName( aRow, "LAYERELECTRICALCONDUCTIVITY" );
820 int layer_mat_col = getColFromName( aRow, "LAYERMATERIAL" );
821
822 if( layer_sort_col < 0 || layer_subclass_col < 0 || layer_art_col < 0 || layer_use_col < 0
823 || layer_cond_col < 0 || layer_er_col < 0 || layer_rho_col < 0 || layer_mat_col < 0 )
824 return -1;
825
826 for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
827 {
828 const single_row& row = rows[rownum];
829
830 if( row.size() != header.size() )
831 {
832 wxLogError( _( "Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
833 rownum,
834 header.size(),
835 row.size() );
836 continue;
837 }
838
839 auto layer_sort = row[layer_sort_col];
840 auto layer_subclass = row[layer_subclass_col];
841 auto layer_art = row[layer_art_col];
842 auto layer_use = row[layer_use_col];
843 auto layer_cond = row[layer_cond_col];
844 auto layer_er = row[layer_er_col];
845 auto layer_rho = row[layer_rho_col];
846 auto layer_mat = row[layer_mat_col];
847
848 if( layer_mat == "AIR" )
849 continue;
850
851 FABMASTER_LAYER layer;
852
853 if( layer_subclass.empty() )
854 {
855 if( layer_cond != "NO" )
856 layer.name = "In.Cu" + layer_sort;
857 else
858 layer.name = "Dielectric" + layer_sort;
859 }
860
861 layer.positive = ( layer_art != "NEGATIVE" );
862
863 layers.emplace( layer.name, layer );
864 }
865
866 return rownum - aRow;
867}
868
869
875size_t FABMASTER::processCustomPads( size_t aRow )
876{
877 size_t rownum = aRow + 2;
878
879 if( rownum >= rows.size() )
880 return -1;
881
882 auto header = rows[aRow];
883 double scale_factor = processScaleFactor( aRow + 1 );
884
885 if( scale_factor <= 0.0 )
886 return -1;
887
888 int pad_subclass_col = getColFromName( aRow, "SUBCLASS" );
889 int pad_shape_name_col = getColFromName( aRow, "PADSHAPENAME" );
890 int pad_grdata_name_col = getColFromName( aRow, "GRAPHICDATANAME" );
891 int pad_grdata_num_col = getColFromName( aRow, "GRAPHICDATANUMBER" );
892 int pad_record_tag_col = getColFromName( aRow, "RECORDTAG" );
893 int pad_grdata1_col = getColFromName( aRow, "GRAPHICDATA1" );
894 int pad_grdata2_col = getColFromName( aRow, "GRAPHICDATA2" );
895 int pad_grdata3_col = getColFromName( aRow, "GRAPHICDATA3" );
896 int pad_grdata4_col = getColFromName( aRow, "GRAPHICDATA4" );
897 int pad_grdata5_col = getColFromName( aRow, "GRAPHICDATA5" );
898 int pad_grdata6_col = getColFromName( aRow, "GRAPHICDATA6" );
899 int pad_grdata7_col = getColFromName( aRow, "GRAPHICDATA7" );
900 int pad_grdata8_col = getColFromName( aRow, "GRAPHICDATA8" );
901 int pad_grdata9_col = getColFromName( aRow, "GRAPHICDATA9" );
902 int pad_stack_name_col = getColFromName( aRow, "PADSTACKNAME" );
903 int pad_refdes_col = getColFromName( aRow, "REFDES" );
904 int pad_pin_num_col = getColFromName( aRow, "PINNUMBER" );
905
906 if( pad_subclass_col < 0 || pad_shape_name_col < 0 || pad_grdata1_col < 0 || pad_grdata2_col < 0
907 || pad_grdata3_col < 0 || pad_grdata4_col < 0 || pad_grdata5_col < 0
908 || pad_grdata6_col < 0 || pad_grdata7_col < 0 || pad_grdata8_col < 0
909 || pad_grdata9_col < 0 || pad_stack_name_col < 0 || pad_refdes_col < 0
910 || pad_pin_num_col < 0 )
911 return -1;
912
913 for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
914 {
915 const single_row& row = rows[rownum];
916
917 if( row.size() != header.size() )
918 {
919 wxLogError( _( "Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
920 rownum,
921 header.size(),
922 row.size() );
923
924 continue;
925 }
926
927 auto pad_layer = row[pad_subclass_col];
928 auto pad_shape_name = row[pad_shape_name_col];
929 auto pad_record_tag = row[pad_record_tag_col];
930
931 GRAPHIC_DATA gr_data;
932 gr_data.graphic_dataname = row[pad_grdata_name_col];
933 gr_data.graphic_datanum = row[pad_grdata_num_col];
934 gr_data.graphic_data1 = row[pad_grdata1_col];
935 gr_data.graphic_data2 = row[pad_grdata2_col];
936 gr_data.graphic_data3 = row[pad_grdata3_col];
937 gr_data.graphic_data4 = row[pad_grdata4_col];
938 gr_data.graphic_data5 = row[pad_grdata5_col];
939 gr_data.graphic_data6 = row[pad_grdata6_col];
940 gr_data.graphic_data7 = row[pad_grdata7_col];
941 gr_data.graphic_data8 = row[pad_grdata8_col];
942 gr_data.graphic_data9 = row[pad_grdata9_col];
943
944 auto pad_stack_name = row[pad_stack_name_col];
945 auto pad_refdes = row[pad_refdes_col];
946 auto pad_pin_num = row[pad_pin_num_col];
947
948 // N.B. We get the FIGSHAPE records as "FIG_SHAPE name". We only want "name"
949 // and we don't process other pad shape records
950 std::string prefix( "FIG_SHAPE " );
951
952 if( pad_shape_name.length() <= prefix.length()
953 || !std::equal( prefix.begin(), prefix.end(), pad_shape_name.begin() ) )
954 {
955 continue;
956 }
957
958 // Custom pads are a series of records with the same record ID but incrementing
959 // Sequence numbers.
960 int id = -1;
961 int seq = -1;
962
963 if( std::sscanf( pad_record_tag.c_str(), "%d %d", &id, &seq ) != 2 )
964 {
965 wxLogError( _( "Invalid format for id string '%s' in custom pad row %zu." ),
966 pad_record_tag.c_str(),
967 rownum );
968 continue;
969 }
970
971 auto name = pad_shape_name.substr( prefix.length() );
972 name += "_" + pad_refdes + "_" + pad_pin_num;
973 auto ret = pad_shapes.emplace( name, FABMASTER_PAD_SHAPE{} );
974
975 auto& custom_pad = ret.first->second;
976
977 // If we were able to insert the pad name, then we need to initialize the
978 // record
979 if( ret.second )
980 {
981 custom_pad.name = name;
982 custom_pad.padstack = pad_stack_name;
983 custom_pad.pinnum = pad_pin_num;
984 custom_pad.refdes = pad_refdes;
985 }
986
987 // At this point we extract the individual graphical elements for processing the complex pad. The
988 // coordinates are in board origin format, so we'll need to fix the offset later when we assign them
989 // to the modules.
990
991 auto gr_item = std::unique_ptr<GRAPHIC_ITEM>( processGraphic( gr_data, scale_factor ) );
992
993 if( gr_item )
994 {
995 gr_item->layer = pad_layer;
996 gr_item->refdes = pad_refdes;
997 gr_item->seq = seq;
998 gr_item->subseq = 0;
999
1001 auto pad_it = custom_pad.elements.emplace( id, graphic_element{} );
1002 auto retval = pad_it.first->second.insert( std::move(gr_item ) );
1003
1004 if( !retval.second )
1005 {
1006 wxLogError( _( "Could not insert graphical item %d into padstack '%s'." ),
1007 seq,
1008 pad_stack_name.c_str() );
1009 }
1010 }
1011 else
1012 {
1013 wxLogError( _( "Unrecognized pad shape primitive '%s' in row %zu." ),
1014 gr_data.graphic_dataname,
1015 rownum );
1016 }
1017 }
1018
1019 return rownum - aRow;
1020}
1021
1022
1024{
1025 GRAPHIC_LINE* new_line = new GRAPHIC_LINE ;
1026
1027 new_line->shape = GR_SHAPE_LINE;
1028 new_line->start_x = KiROUND( readDouble( aData.graphic_data1 ) * aScale );
1029 new_line->start_y = -KiROUND( readDouble( aData.graphic_data2 ) * aScale );
1030 new_line->end_x = KiROUND( readDouble( aData.graphic_data3 ) * aScale );
1031 new_line->end_y = -KiROUND( readDouble( aData.graphic_data4 ) * aScale );
1032 new_line->width = KiROUND( readDouble( aData.graphic_data5 ) * aScale );
1033
1034 return new_line;
1035}
1036
1038{
1039 GRAPHIC_ARC* new_arc = new GRAPHIC_ARC ;
1040
1041 new_arc->shape = GR_SHAPE_ARC;
1042 new_arc->start_x = KiROUND( readDouble( aData.graphic_data1 ) * aScale );
1043 new_arc->start_y = -KiROUND( readDouble( aData.graphic_data2 ) * aScale );
1044 new_arc->end_x = KiROUND( readDouble( aData.graphic_data3 ) * aScale );
1045 new_arc->end_y = -KiROUND( readDouble( aData.graphic_data4 ) * aScale );
1046 new_arc->center_x = KiROUND( readDouble( aData.graphic_data5 ) * aScale );
1047 new_arc->center_y = -KiROUND( readDouble( aData.graphic_data6 ) * aScale );
1048 new_arc->radius = KiROUND( readDouble( aData.graphic_data7 ) * aScale );
1049 new_arc->width = KiROUND( readDouble( aData.graphic_data8 ) * aScale );
1050
1051 new_arc->clockwise = ( aData.graphic_data9 != "COUNTERCLOCKWISE" );
1052
1053 EDA_ANGLE startangle( VECTOR2I( new_arc->start_x, new_arc->start_y )
1054 - VECTOR2I( new_arc->center_x, new_arc->center_y ) );
1055 EDA_ANGLE endangle( VECTOR2I( new_arc->end_x, new_arc->end_y )
1056 - VECTOR2I( new_arc->center_x, new_arc->center_y ) );
1058
1059 startangle.Normalize();
1060 endangle.Normalize();
1061
1062 VECTOR2I center( new_arc->center_x, new_arc->center_y );
1063 VECTOR2I start( new_arc->start_x, new_arc->start_y );
1064 VECTOR2I mid( new_arc->start_x, new_arc->start_y );
1065 VECTOR2I end( new_arc->end_x, new_arc->end_y );
1066
1067 angle = endangle - startangle;
1068
1069 if( new_arc->clockwise && angle < ANGLE_0 )
1070 angle += ANGLE_360;
1071 if( !new_arc->clockwise && angle > ANGLE_0 )
1072 angle -= ANGLE_360;
1073
1074 if( start == end )
1075 angle = -ANGLE_360;
1076
1077 RotatePoint( mid, center, -angle / 2.0 );
1078
1079 if( start == end )
1080 new_arc->shape = GR_SHAPE_CIRCLE;
1081
1082 new_arc->result = SHAPE_ARC( start, mid, end, 0 );
1083
1084 return new_arc;
1085}
1086
1088{
1089 GRAPHIC_RECTANGLE* new_rect = new GRAPHIC_RECTANGLE;
1090
1091 new_rect->shape = GR_SHAPE_RECTANGLE;
1092 new_rect->start_x = KiROUND( readDouble( aData.graphic_data1 ) * aScale );
1093 new_rect->start_y = -KiROUND( readDouble( aData.graphic_data2 ) * aScale );
1094 new_rect->end_x = KiROUND( readDouble( aData.graphic_data3 ) * aScale );
1095 new_rect->end_y = -KiROUND( readDouble( aData.graphic_data4 ) * aScale );
1096 new_rect->fill = aData.graphic_data5 == "1";
1097 new_rect->width = 0;
1098
1099 return new_rect;
1100}
1101
1103{
1104 GRAPHIC_TEXT* new_text = new GRAPHIC_TEXT;
1105
1106 new_text->shape = GR_SHAPE_TEXT;
1107 new_text->start_x = KiROUND( readDouble( aData.graphic_data1 ) * aScale );
1108 new_text->start_y = -KiROUND( readDouble( aData.graphic_data2 ) * aScale );
1109 new_text->rotation = KiROUND( readDouble( aData.graphic_data3 ) );
1110 new_text->mirror = ( aData.graphic_data4 == "YES" );
1111
1112 if( aData.graphic_data5 == "RIGHT" )
1113 new_text->orient = GR_TEXT_H_ALIGN_RIGHT;
1114 else if( aData.graphic_data5 == "CENTER" )
1115 new_text->orient = GR_TEXT_H_ALIGN_CENTER;
1116 else
1117 new_text->orient = GR_TEXT_H_ALIGN_LEFT;
1118
1119 std::vector<std::string> toks = split( aData.graphic_data6, " \t" );
1120
1121 if( toks.size() < 8 )
1122 {
1123 // We log the error here but continue in the case of too few tokens
1124 wxLogError( _( "Invalid token count. Expected 8 but found %zu." ), toks.size() );
1125 new_text->height = 0;
1126 new_text->width = 0;
1127 new_text->ital = false;
1128 new_text->thickness = 0;
1129 }
1130 else
1131 {
1132 // 0 = size
1133 // 1 = font
1134 new_text->height = KiROUND( readDouble( toks[2] ) * aScale );
1135 new_text->width = KiROUND( readDouble( toks[3] ) * aScale );
1136 new_text->ital = readDouble( toks[4] ) != 0.0;
1137 // 5 = character spacing
1138 // 6 = line spacing
1139 new_text->thickness = KiROUND( readDouble( toks[7] ) * aScale );
1140 }
1141
1142 new_text->text = aData.graphic_data7;
1143 return new_text;
1144}
1145
1146
1148{
1149 GRAPHIC_ITEM* retval = nullptr;
1150
1151 if( aData.graphic_dataname == "LINE" )
1152 retval = processLine( aData, aScale );
1153 else if( aData.graphic_dataname == "ARC" )
1154 retval = processArc( aData, aScale );
1155 else if( aData.graphic_dataname == "RECTANGLE" )
1156 retval = processRectangle( aData, aScale );
1157 else if( aData.graphic_dataname == "TEXT" )
1158 retval = processText( aData, aScale );
1159
1160 if( retval && !aData.graphic_data10.empty() )
1161 {
1162 if( aData.graphic_data10 == "CONNECT" )
1163 retval->type = GR_TYPE_CONNECT;
1164 else if( aData.graphic_data10 == "NOTCONNECT" )
1165 retval->type = GR_TYPE_NOTCONNECT;
1166 else if( aData.graphic_data10 == "SHAPE" )
1167 retval->type = GR_TYPE_NOTCONNECT;
1168 else if( aData.graphic_data10 == "VOID" )
1169 retval->type = GR_TYPE_NOTCONNECT;
1170 else if( aData.graphic_data10 == "POLYGON" )
1171 retval->type = GR_TYPE_NOTCONNECT;
1172 else
1173 retval->type = GR_TYPE_NONE;
1174 }
1175
1176 return retval;
1177}
1178
1179
1185size_t FABMASTER::processGeometry( size_t aRow )
1186{
1187 size_t rownum = aRow + 2;
1188
1189 if( rownum >= rows.size() )
1190 return -1;
1191
1192 const single_row& header = rows[aRow];
1193 double scale_factor = processScaleFactor( aRow + 1 );
1194
1195 if( scale_factor <= 0.0 )
1196 return -1;
1197
1198 int geo_name_col = getColFromName( aRow, "GRAPHICDATANAME" );
1199 int geo_num_col = getColFromName( aRow, "GRAPHICDATANUMBER" );
1200 int geo_tag_col = getColFromName( aRow, "RECORDTAG" );
1201 int geo_grdata1_col = getColFromName( aRow, "GRAPHICDATA1" );
1202 int geo_grdata2_col = getColFromName( aRow, "GRAPHICDATA2" );
1203 int geo_grdata3_col = getColFromName( aRow, "GRAPHICDATA3" );
1204 int geo_grdata4_col = getColFromName( aRow, "GRAPHICDATA4" );
1205 int geo_grdata5_col = getColFromName( aRow, "GRAPHICDATA5" );
1206 int geo_grdata6_col = getColFromName( aRow, "GRAPHICDATA6" );
1207 int geo_grdata7_col = getColFromName( aRow, "GRAPHICDATA7" );
1208 int geo_grdata8_col = getColFromName( aRow, "GRAPHICDATA8" );
1209 int geo_grdata9_col = getColFromName( aRow, "GRAPHICDATA9" );
1210 int geo_subclass_col = getColFromName( aRow, "SUBCLASS" );
1211 int geo_sym_name_col = getColFromName( aRow, "SYMNAME" );
1212 int geo_refdes_col = getColFromName( aRow, "REFDES" );
1213
1214 if( geo_name_col < 0 || geo_num_col < 0 || geo_grdata1_col < 0 || geo_grdata2_col < 0
1215 || geo_grdata3_col < 0 || geo_grdata4_col < 0 || geo_grdata5_col < 0
1216 || geo_grdata6_col < 0 || geo_grdata7_col < 0 || geo_grdata8_col < 0
1217 || geo_grdata9_col < 0 || geo_subclass_col < 0 || geo_sym_name_col < 0
1218 || geo_refdes_col < 0 )
1219 return -1;
1220
1221 for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
1222 {
1223 const single_row& row = rows[rownum];
1224
1225 if( row.size() != header.size() )
1226 {
1227 wxLogError( _( "Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
1228 rownum,
1229 header.size(),
1230 row.size() );
1231 continue;
1232 }
1233
1234 auto geo_tag = row[geo_tag_col];
1235
1236 GRAPHIC_DATA gr_data;
1237 gr_data.graphic_dataname = row[geo_name_col];
1238 gr_data.graphic_datanum = row[geo_num_col];
1239 gr_data.graphic_data1 = row[geo_grdata1_col];
1240 gr_data.graphic_data2 = row[geo_grdata2_col];
1241 gr_data.graphic_data3 = row[geo_grdata3_col];
1242 gr_data.graphic_data4 = row[geo_grdata4_col];
1243 gr_data.graphic_data5 = row[geo_grdata5_col];
1244 gr_data.graphic_data6 = row[geo_grdata6_col];
1245 gr_data.graphic_data7 = row[geo_grdata7_col];
1246 gr_data.graphic_data8 = row[geo_grdata8_col];
1247 gr_data.graphic_data9 = row[geo_grdata9_col];
1248
1249 auto geo_refdes = row[geo_refdes_col];
1250
1251 // Grouped graphics are a series of records with the same record ID but incrementing
1252 // Sequence numbers.
1253 int id = -1;
1254 int seq = -1;
1255 int subseq = 0;
1256
1257 if( std::sscanf( geo_tag.c_str(), "%d %d %d", &id, &seq, &subseq ) < 2 )
1258 {
1259 wxLogError( _( "Invalid format for record_tag string '%s' in row %zu." ),
1260 geo_tag.c_str(),
1261 rownum );
1262 continue;
1263 }
1264
1265 auto gr_item = std::unique_ptr<GRAPHIC_ITEM>( processGraphic( gr_data, scale_factor ) );
1266
1267 if( !gr_item )
1268 {
1269 wxLogDebug( wxT( "Unhandled graphic item '%s' in row %zu." ),
1270 gr_data.graphic_dataname.c_str(),
1271 geo_tag.c_str(),
1272 rownum );
1273 continue;
1274 }
1275
1276 gr_item->layer = row[geo_subclass_col];
1277 gr_item->seq = seq;
1278 gr_item->subseq = subseq;
1279
1280 if( geo_refdes.empty() )
1281 {
1282 if( board_graphics.empty() || board_graphics.back().id != id )
1283 {
1284 GEOM_GRAPHIC new_gr;
1285 new_gr.subclass = row[geo_subclass_col];
1286 new_gr.refdes = row[geo_refdes_col];
1287 new_gr.name = row[geo_sym_name_col];
1288 new_gr.id = id;
1289 new_gr.elements = std::make_unique<graphic_element>();
1290 board_graphics.push_back( std::move( new_gr ) );
1291 }
1292
1293 GEOM_GRAPHIC& graphic = board_graphics.back();
1294 graphic.elements->emplace( std::move( gr_item ) );
1295 }
1296 else
1297 {
1298 auto sym_gr_it = comp_graphics.emplace( geo_refdes,
1299 std::map<int, GEOM_GRAPHIC>{} );
1300 auto map_it = sym_gr_it.first->second.emplace( id, GEOM_GRAPHIC{} );
1301 auto& gr = map_it.first;
1302
1303 if( map_it.second )
1304 {
1305 gr->second.subclass = row[geo_subclass_col];
1306 gr->second.refdes = row[geo_refdes_col];
1307 gr->second.name = row[geo_sym_name_col];
1308 gr->second.id = id;
1309 gr->second.elements = std::make_unique<graphic_element>();
1310 }
1311
1312 auto result = gr->second.elements->emplace( std::move( gr_item ) );
1313 }
1314 }
1315
1316 return rownum - aRow;
1317}
1318
1319
1323size_t FABMASTER::processVias( size_t aRow )
1324{
1325 size_t rownum = aRow + 2;
1326
1327 if( rownum >= rows.size() )
1328 return -1;
1329
1330 const single_row& header = rows[aRow];
1331 double scale_factor = processScaleFactor( aRow + 1 );
1332
1333 if( scale_factor <= 0.0 )
1334 return -1;
1335
1336 int viax_col = getColFromName( aRow, "VIAX" );
1337 int viay_col = getColFromName( aRow, "VIAY" );
1338 int padstack_name_col = getColFromName( aRow, "PADSTACKNAME" );
1339 int net_name_col = getColFromName( aRow, "NETNAME" );
1340 int test_point_col = getColFromName( aRow, "TESTPOINT" );
1341
1342 if( viax_col < 0 || viay_col < 0 || padstack_name_col < 0 || net_name_col < 0
1343 || test_point_col < 0 )
1344 return -1;
1345
1346 for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
1347 {
1348 const single_row& row = rows[rownum];
1349
1350 if( row.size() != header.size() )
1351 {
1352 wxLogError( _( "Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
1353 rownum,
1354 header.size(),
1355 row.size() );
1356 continue;
1357 }
1358
1359 vias.emplace_back( std::make_unique<FM_VIA>() );
1360 auto& via = vias.back();
1361
1362 via->x = KiROUND( readDouble( row[viax_col] ) * scale_factor );
1363 via->y = -KiROUND( readDouble( row[viay_col] ) * scale_factor );
1364 via->padstack = row[padstack_name_col];
1365 via->net = row[net_name_col];
1366 via->test_point = ( row[test_point_col] == "YES" );
1367 }
1368
1369 return rownum - aRow;
1370}
1371
1372
1378size_t FABMASTER::processTraces( size_t aRow )
1379{
1380 size_t rownum = aRow + 2;
1381
1382 if( rownum >= rows.size() )
1383 return -1;
1384
1385 const single_row& header = rows[aRow];
1386 double scale_factor = processScaleFactor( aRow + 1 );
1387
1388 if( scale_factor <= 0.0 )
1389 return -1;
1390
1391 int class_col = getColFromName( aRow, "CLASS" );
1392 int layer_col = getColFromName( aRow, "SUBCLASS" );
1393 int grdata_name_col = getColFromName( aRow, "GRAPHICDATANAME" );
1394 int grdata_num_col = getColFromName( aRow, "GRAPHICDATANUMBER" );
1395 int tag_col = getColFromName( aRow, "RECORDTAG" );
1396 int grdata1_col = getColFromName( aRow, "GRAPHICDATA1" );
1397 int grdata2_col = getColFromName( aRow, "GRAPHICDATA2" );
1398 int grdata3_col = getColFromName( aRow, "GRAPHICDATA3" );
1399 int grdata4_col = getColFromName( aRow, "GRAPHICDATA4" );
1400 int grdata5_col = getColFromName( aRow, "GRAPHICDATA5" );
1401 int grdata6_col = getColFromName( aRow, "GRAPHICDATA6" );
1402 int grdata7_col = getColFromName( aRow, "GRAPHICDATA7" );
1403 int grdata8_col = getColFromName( aRow, "GRAPHICDATA8" );
1404 int grdata9_col = getColFromName( aRow, "GRAPHICDATA9" );
1405 int netname_col = getColFromName( aRow, "NETNAME" );
1406
1407 if( class_col < 0 || layer_col < 0 || grdata_name_col < 0 || grdata_num_col < 0
1408 || tag_col < 0 || grdata1_col < 0 || grdata2_col < 0 || grdata3_col < 0
1409 || grdata4_col < 0 || grdata5_col < 0 || grdata6_col < 0 || grdata7_col < 0
1410 || grdata8_col < 0 || grdata9_col < 0 || netname_col < 0 )
1411 return -1;
1412
1413 for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
1414 {
1415 const single_row& row = rows[rownum];
1416
1417 if( row.size() != header.size() )
1418 {
1419 wxLogError( _( "Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
1420 rownum,
1421 header.size(),
1422 row.size() );
1423 continue;
1424 }
1425
1426 GRAPHIC_DATA gr_data;
1427 gr_data.graphic_dataname = row[grdata_name_col];
1428 gr_data.graphic_datanum = row[grdata_num_col];
1429 gr_data.graphic_data1 = row[grdata1_col];
1430 gr_data.graphic_data2 = row[grdata2_col];
1431 gr_data.graphic_data3 = row[grdata3_col];
1432 gr_data.graphic_data4 = row[grdata4_col];
1433 gr_data.graphic_data5 = row[grdata5_col];
1434 gr_data.graphic_data6 = row[grdata6_col];
1435 gr_data.graphic_data7 = row[grdata7_col];
1436 gr_data.graphic_data8 = row[grdata8_col];
1437 gr_data.graphic_data9 = row[grdata9_col];
1438
1439 const std::string& geo_tag = row[tag_col];
1440 // Grouped graphics are a series of records with the same record ID but incrementing
1441 // Sequence numbers.
1442 int id = -1;
1443 int seq = -1;
1444 int subseq = 0;
1445
1446 if( std::sscanf( geo_tag.c_str(), "%d %d %d", &id, &seq, &subseq ) < 2 )
1447 {
1448 wxLogError( _( "Invalid format for record_tag string '%s' in row %zu." ),
1449 geo_tag.c_str(),
1450 rownum );
1451 continue;
1452 }
1453
1454 auto gr_item = std::unique_ptr<GRAPHIC_ITEM>( processGraphic( gr_data, scale_factor ) );
1455
1456 if( !gr_item )
1457 {
1458 wxLogDebug( _( "Unhandled graphic item '%s' in row %zu." ),
1459 gr_data.graphic_dataname.c_str(),
1460 rownum );
1461 continue;
1462 }
1463
1464 auto new_trace = std::make_unique<TRACE>();
1465 new_trace->id = id;
1466 new_trace->layer = row[layer_col];
1467 new_trace->netname = row[netname_col];
1468 new_trace->lclass = row[class_col];
1469
1470 gr_item->layer = row[layer_col];
1471 gr_item->seq = seq;
1472 gr_item->subseq = subseq;
1473
1474 // Collect the reference designator positions for the footprints later
1475 if( new_trace->lclass == "REF DES" )
1476 {
1477 auto result = refdes.emplace( std::move( new_trace ) );
1478 auto& ref = *result.first;
1479 ref->segment.emplace( std::move( gr_item ) );
1480 }
1481 else if( gr_item->width == 0 )
1482 {
1483 auto result = zones.emplace( std::move( new_trace ) );
1484 auto& zone = *result.first;
1485 auto gr_result = zone->segment.emplace( std::move( gr_item ) );
1486
1487 if( !gr_result.second )
1488 {
1489 wxLogError( _( "Duplicate item for ID %d and sequence %d in row %zu." ),
1490 id,
1491 seq,
1492 rownum );
1493 }
1494
1495 }
1496 else
1497 {
1498 auto result = traces.emplace( std::move( new_trace ) );
1499 auto& trace = *result.first;
1500 auto gr_result = trace->segment.emplace( std::move( gr_item ) );
1501
1502 if( !gr_result.second )
1503 {
1504 wxLogError( _( "Duplicate item for ID %d and sequence %d in row %zu." ),
1505 id,
1506 seq,
1507 rownum );
1508 }
1509 }
1510 }
1511
1512 return rownum - aRow;
1513}
1514
1515
1516FABMASTER::SYMTYPE FABMASTER::parseSymType( const std::string& aSymType )
1517{
1518 if( aSymType == "PACKAGE" )
1519 return SYMTYPE_PACKAGE;
1520 else if( aSymType == "DRAFTING")
1521 return SYMTYPE_DRAFTING;
1522 else if( aSymType == "MECHANICAL" )
1523 return SYMTYPE_MECH;
1524 else if( aSymType == "FORMAT" )
1525 return SYMTYPE_FORMAT;
1526
1527 return SYMTYPE_NONE;
1528}
1529
1530
1532{
1533 if( aCmpClass == "IO" )
1534 return COMPCLASS_IO;
1535 else if( aCmpClass == "IC" )
1536 return COMPCLASS_IC;
1537 else if( aCmpClass == "DISCRETE" )
1538 return COMPCLASS_DISCRETE;
1539
1540 return COMPCLASS_NONE;
1541}
1542
1547size_t FABMASTER::processFootprints( size_t aRow )
1548{
1549 size_t rownum = aRow + 2;
1550
1551 if( rownum >= rows.size() )
1552 return -1;
1553
1554 const single_row& header = rows[aRow];
1555 double scale_factor = processScaleFactor( aRow + 1 );
1556
1557 if( scale_factor <= 0.0 )
1558 return -1;
1559
1560 int refdes_col = getColFromName( aRow, "REFDES" );
1561 int compclass_col = getColFromName( aRow, "COMPCLASS" );
1562 int comppartnum_col = getColFromName( aRow, "COMPPARTNUMBER" );
1563 int compheight_col = getColFromName( aRow, "COMPHEIGHT" );
1564 int compdevlabelcol = getColFromName( aRow, "COMPDEVICELABEL" );
1565 int compinscode_col = getColFromName( aRow, "COMPINSERTIONCODE" );
1566 int symtype_col = getColFromName( aRow, "SYMTYPE" );
1567 int symname_col = getColFromName( aRow, "SYMNAME" );
1568 int symmirror_col = getColFromName( aRow, "SYMMIRROR" );
1569 int symrotate_col = getColFromName( aRow, "SYMROTATE" );
1570 int symx_col = getColFromName( aRow, "SYMX" );
1571 int symy_col = getColFromName( aRow, "SYMY" );
1572 int compvalue_col = getColFromName( aRow, "COMPVALUE" );
1573 int comptol_col = getColFromName( aRow, "COMPTOL" );
1574 int compvolt_col = getColFromName( aRow, "COMPVOLTAGE" );
1575
1576 if( refdes_col < 0 || compclass_col < 0 || comppartnum_col < 0 || compheight_col < 0
1577 || compdevlabelcol < 0 || compinscode_col < 0 || symtype_col < 0 || symname_col < 0
1578 || symmirror_col < 0 || symrotate_col < 0 || symx_col < 0 || symy_col < 0
1579 || compvalue_col < 0 || comptol_col < 0 || compvolt_col < 0 )
1580 return -1;
1581
1582 for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
1583 {
1584 const single_row& row = rows[rownum];
1585
1586 if( row.size() != header.size() )
1587 {
1588 wxLogError( _( "Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
1589 rownum,
1590 header.size(),
1591 row.size() );
1592 continue;
1593 }
1594
1595 auto cmp = std::make_unique<COMPONENT>();
1596
1597 cmp->refdes = row[refdes_col];
1598 cmp->cclass = parseCompClass( row[compclass_col] );
1599 cmp->pn = row[comppartnum_col];
1600 cmp->height = row[compheight_col];
1601 cmp->dev_label = row[compdevlabelcol];
1602 cmp->insert_code = row[compinscode_col];
1603 cmp->type = parseSymType( row[symtype_col] );
1604 cmp->name = row[symname_col];
1605 cmp->mirror = ( row[symmirror_col] == "YES" );
1606 cmp->rotate = readDouble( row[symrotate_col] );
1607 cmp->x = KiROUND( readDouble( row[symx_col] ) * scale_factor );
1608 cmp->y = -KiROUND( readDouble( row[symy_col] ) * scale_factor );
1609 cmp->value = row[compvalue_col];
1610 cmp->tol = row[comptol_col];
1611 cmp->voltage = row[compvolt_col];
1612
1613 auto vec = components.find( cmp->refdes );
1614
1615 if( vec == components.end() )
1616 {
1617 auto retval = components.insert( std::make_pair( cmp->refdes, std::vector<std::unique_ptr<COMPONENT>>{} ) );
1618
1619 vec = retval.first;
1620 }
1621
1622 vec->second.push_back( std::move( cmp ) );
1623 }
1624
1625 return rownum - aRow;
1626}
1627
1628
1632size_t FABMASTER::processPins( size_t aRow )
1633{
1634 size_t rownum = aRow + 2;
1635
1636 if( rownum >= rows.size() )
1637 return -1;
1638
1639 const single_row& header = rows[aRow];
1640 double scale_factor = processScaleFactor( aRow + 1 );
1641
1642 if( scale_factor <= 0.0 )
1643 return -1;
1644
1645 int symname_col = getColFromName( aRow, "SYMNAME" );
1646 int symmirror_col = getColFromName( aRow, "SYMMIRROR" );
1647 int pinname_col = getColFromName( aRow, "PINNAME" );
1648 int pinnum_col = getColFromName( aRow, "PINNUMBER" );
1649 int pinx_col = getColFromName( aRow, "PINX" );
1650 int piny_col = getColFromName( aRow, "PINY" );
1651 int padstack_col = getColFromName( aRow, "PADSTACKNAME" );
1652 int refdes_col = getColFromName( aRow, "REFDES" );
1653 int pinrot_col = getColFromName( aRow, "PINROTATION" );
1654 int testpoint_col = getColFromName( aRow, "TESTPOINT" );
1655
1656 if( symname_col < 0 ||symmirror_col < 0 || pinname_col < 0 || pinnum_col < 0 || pinx_col < 0
1657 || piny_col < 0 || padstack_col < 0 || refdes_col < 0 || pinrot_col < 0
1658 || testpoint_col < 0 )
1659 return -1;
1660
1661 for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
1662 {
1663 const single_row& row = rows[rownum];
1664
1665 if( row.size() != header.size() )
1666 {
1667 wxLogError( _( "Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
1668 rownum,
1669 header.size(),
1670 row.size() );
1671 continue;
1672 }
1673
1674 auto pin = std::make_unique<PIN>();
1675
1676 pin->name = row[symname_col];
1677 pin->mirror = ( row[symmirror_col] == "YES" );
1678 pin->pin_name = row[pinname_col];
1679 pin->pin_number = row[pinnum_col];
1680 pin->pin_x = KiROUND( readDouble( row[pinx_col] ) * scale_factor );
1681 pin->pin_y = -KiROUND( readDouble( row[piny_col] ) * scale_factor );
1682 pin->padstack = row[padstack_col];
1683 pin->refdes = row[refdes_col];
1684 pin->rotation = readDouble( row[pinrot_col] );
1685
1686 auto map_it = pins.find( pin->refdes );
1687
1688 if( map_it == pins.end() )
1689 {
1690 auto retval = pins.insert( std::make_pair( pin->refdes, std::set<std::unique_ptr<PIN>, PIN::BY_NUM>{} ) );
1691 map_it = retval.first;
1692 }
1693
1694 map_it->second.insert( std::move( pin ) );
1695 }
1696
1697 return rownum - aRow;
1698}
1699
1700
1704size_t FABMASTER::processNets( size_t aRow )
1705{
1706 size_t rownum = aRow + 2;
1707
1708 if( rownum >= rows.size() )
1709 return -1;
1710
1711 const single_row& header = rows[aRow];
1712 double scale_factor = processScaleFactor( aRow + 1 );
1713
1714 if( scale_factor <= 0.0 )
1715 return -1;
1716
1717 int netname_col = getColFromName( aRow, "NETNAME" );
1718 int refdes_col = getColFromName( aRow, "REFDES" );
1719 int pinnum_col = getColFromName( aRow, "PINNUMBER" );
1720 int pinname_col = getColFromName( aRow, "PINNAME" );
1721 int pingnd_col = getColFromName( aRow, "PINGROUND" );
1722 int pinpwr_col = getColFromName( aRow, "PINPOWER" );
1723
1724 if( netname_col < 0 || refdes_col < 0 || pinnum_col < 0 || pinname_col < 0 || pingnd_col < 0
1725 || pinpwr_col < 0 )
1726 return -1;
1727
1728 for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
1729 {
1730 const single_row& row = rows[rownum];
1731
1732 if( row.size() != header.size() )
1733 {
1734 wxLogError( _( "Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
1735 rownum,
1736 header.size(),
1737 row.size() );
1738 continue;
1739 }
1740
1741 NETNAME new_net;
1742 new_net.name = row[netname_col];
1743 new_net.refdes = row[refdes_col];
1744 new_net.pin_num = row[pinnum_col];
1745 new_net.pin_name = row[pinname_col];
1746 new_net.pin_gnd = ( row[pingnd_col] == "YES" );
1747 new_net.pin_pwr = ( row[pinpwr_col] == "YES" );
1748
1749 pin_nets.emplace( std::make_pair( new_net.refdes, new_net.pin_num ), new_net );
1750 netnames.insert( row[netname_col] );
1751 }
1752
1753 return rownum - aRow;
1754}
1755
1756
1758{
1759
1760 for( size_t i = 0; i < rows.size(); )
1761 {
1762 auto type = detectType( i );
1763
1764 switch( type )
1765 {
1766 case EXTRACT_PADSTACKS:
1767 {
1771 assignLayers();
1772 int retval = processPadStacks( i );
1773
1774 i += std::max( retval, 1 );
1775 break;
1776 }
1777
1779 {
1780 int retval = processLayers( i );
1781
1782 i += std::max( retval, 1 );
1783 break;
1784 }
1785
1787 {
1788 int retval = processSimpleLayers( i );
1789
1790 i += std::max( retval, 1 );
1791 break;
1792 }
1793
1794 case EXTRACT_VIAS:
1795 {
1796 int retval = processVias( i );
1797
1798 i += std::max( retval, 1 );
1799 break;
1800 }
1801
1802 case EXTRACT_TRACES:
1803 {
1804 int retval = processTraces( i );
1805
1806 i += std::max( retval, 1 );
1807 break;
1808 }
1809
1810 case EXTRACT_REFDES:
1811 {
1812 int retval = processFootprints( i );
1813
1814 i += std::max( retval, 1 );
1815 break;
1816 }
1817
1818 case EXTRACT_NETS:
1819 {
1820 int retval = processNets( i );
1821
1822 i += std::max( retval, 1 );
1823 break;
1824 }
1825
1826 case EXTRACT_GRAPHICS:
1827 {
1828 int retval = processGeometry( i );
1829
1830 i += std::max( retval, 1 );
1831 break;
1832 }
1833
1834 case EXTRACT_PINS:
1835 {
1836 int retval = processPins( i );
1837
1838 i += std::max( retval, 1 );
1839 break;
1840 }
1841
1842 case EXTRACT_PAD_SHAPES:
1843 {
1844 int retval = processCustomPads( i );
1845
1846 i += std::max( retval, 1 );
1847 break;
1848 }
1849
1850 default:
1851 ++i;
1852 break;
1853 }
1854
1855 }
1856
1857 return true;
1858}
1859
1860
1862{
1863 for( auto& zone : zones )
1864 {
1865 checkpoint();
1866
1867 if( IsCopperLayer( getLayer( zone->layer ) ) || zone->layer == "ALL" )
1868 {
1869 loadZone( aBoard, zone );
1870 }
1871 else
1872 {
1873 if( zone->layer == "OUTLINE" || zone->layer == "DESIGN_OUTLINE" )
1874 {
1875 loadOutline( aBoard, zone );
1876 }
1877 else
1878 {
1879 loadPolygon( aBoard, zone );
1880 }
1881 }
1882 }
1883
1894 std::set<ZONE*> zones_to_delete;
1895
1896 for( auto zone : aBoard->Zones() )
1897 {
1899 if( zone->GetNetCode() > 0 )
1900 {
1901 zones_to_delete.insert( zone );
1902 }
1903 }
1904
1905 for( auto zone1 : aBoard->Zones() )
1906 {
1908 if( zone1->GetNetCode() > 0 )
1909 continue;
1910
1911 SHAPE_LINE_CHAIN& outline1 = zone1->Outline()->Outline( 0 );
1912 std::vector<size_t> overlaps( aBoard->GetNetInfo().GetNetCount() + 1, 0 );
1913 std::vector<std::vector<ZONE*>> possible_deletions( overlaps.size() );
1914
1915 for( auto zone2 : aBoard->Zones() )
1916 {
1917 if( zone2->GetNetCode() <= 0 )
1918 continue;
1919
1920 SHAPE_LINE_CHAIN& outline2 = zone2->Outline()->Outline( 0 );
1921
1922 if( zone1->GetLayer() != zone2->GetLayer() )
1923 continue;
1924
1925 if( !outline1.BBox().Intersects( outline2.BBox() ) )
1926 continue;
1927
1928 for( auto& pt1 : outline1.CPoints() )
1929 {
1931 if( outline2.PointOnEdge( pt1, 1 ) )
1932 overlaps[ zone2->GetNetCode() ]++;
1933 }
1934
1935 for( auto& pt2 : outline2.CPoints() )
1936 {
1939 if( outline1.PointOnEdge( pt2, 1 ) )
1940 overlaps[ zone2->GetNetCode() ]++;
1941 }
1942 }
1943
1944 size_t max_net = 0;
1945 size_t max_net_id = 0;
1946
1947 for( size_t el = 1; el < overlaps.size(); ++el )
1948 {
1949 if( overlaps[el] > max_net )
1950 {
1951 max_net = overlaps[el];
1952 max_net_id = el;
1953 }
1954 }
1955
1956 if( max_net > 0 )
1957 zone1->SetNetCode( max_net_id );
1958 }
1959
1960 for( auto zone : zones_to_delete )
1961 {
1962 aBoard->Remove( zone );
1963 delete zone;
1964 }
1965
1966 return true;
1967}
1968
1969
1971{
1972 const NETNAMES_MAP& netinfo = aBoard->GetNetInfo().NetsByName();
1973 const auto& ds = aBoard->GetDesignSettings();
1974
1975 for( auto& mod : components )
1976 {
1977 checkpoint();
1978
1979 bool has_multiple = mod.second.size() > 1;
1980
1981 for( int i = 0; i < mod.second.size(); ++i )
1982 {
1983 auto& src = mod.second[i];
1984
1985 FOOTPRINT* fp = new FOOTPRINT( aBoard );
1986
1987 wxString mod_ref = src->name;
1988 wxString lib_ref = m_filename.GetName();
1989
1990 if( has_multiple )
1991 mod_ref.Append( wxString::Format( wxT( "_%d" ), i ) );
1992
1993 ReplaceIllegalFileNameChars( lib_ref, '_' );
1994 ReplaceIllegalFileNameChars( mod_ref, '_' );
1995
1996 wxString key = !lib_ref.empty() ? lib_ref + wxT( ":" ) + mod_ref : mod_ref;
1997
1998 LIB_ID fpID;
1999 fpID.Parse( key, true );
2000 fp->SetFPID( fpID );
2001
2002 fp->SetPosition( wxPoint( src->x, src->y ) );
2003 fp->SetOrientationDegrees( -src->rotate );
2004
2005 // KiCad netlisting requires parts to have non-digit + digit annotation.
2006 // If the reference begins with a number, we prepend 'UNK' (unknown) for the source designator
2007 wxString reference = src->refdes;
2008
2009 if( !std::isalpha( src->refdes[0] ) )
2010 reference.Prepend( "UNK" );
2011
2012 fp->SetReference( reference );
2013
2014 fp->SetValue( src->value );
2015 fp->Value().SetLayer( F_Fab );
2016 fp->Value().SetVisible( false );
2017
2018 for( auto& ref : refdes )
2019 {
2020 const GRAPHIC_TEXT *lsrc =
2021 static_cast<const GRAPHIC_TEXT*>( ( *( ref->segment.begin() ) ).get() );
2022
2023 if( lsrc->text == src->refdes )
2024 {
2025 FP_TEXT* txt = nullptr;
2026 PCB_LAYER_ID layer = getLayer( ref->layer );
2027
2028 if( !IsPcbLayer( layer ) )
2029 {
2030 wxLogDebug("The layer %s is not mapped?\n", ref->layer.c_str() );
2031 continue;
2032 }
2033
2034 if( layer == F_SilkS || layer == B_SilkS )
2035 txt = &( fp->Reference() );
2036 else
2037 txt = new FP_TEXT( fp );
2038
2039 if( src->mirror )
2040 {
2041 txt->SetLayer( FlipLayer( layer ) );
2042 txt->SetTextPos( wxPoint( lsrc->start_x, 2 * src->y - ( lsrc->start_y - lsrc->height / 2 ) ) );
2043 }
2044 else
2045 {
2046 txt->SetLayer( layer );
2047 txt->SetTextPos( wxPoint( lsrc->start_x, lsrc->start_y - lsrc->height / 2 ) );
2048 }
2049
2050 txt->SetText( lsrc->text );
2051 txt->SetItalic( lsrc->ital );
2052 txt->SetTextThickness( lsrc->thickness );
2053 txt->SetTextHeight( lsrc->height );
2054 txt->SetTextWidth( lsrc->width );
2055 txt->SetHorizJustify( lsrc->orient );
2056 txt->SetLocalCoord();
2057
2058 if( txt != &fp->Reference() )
2059 fp->Add( txt, ADD_MODE::APPEND );
2060 }
2061 }
2062
2065 fp->SetLayer( F_Cu );
2066
2067 auto gr_it = comp_graphics.find( src->refdes );
2068
2069 if( gr_it == comp_graphics.end() )
2070 {
2071 continue;
2072 //TODO: Error
2073 }
2074
2075 for( auto& gr_ref : gr_it->second )
2076 {
2077 auto& graphic = gr_ref.second;
2078
2079 for( auto& seg : *graphic.elements )
2080 {
2081 PCB_LAYER_ID layer = Dwgs_User;
2082
2083 if( IsPcbLayer( getLayer( seg->layer ) ) )
2084 layer = getLayer( seg->layer );
2085
2086 STROKE_PARAMS defaultStroke( ds.GetLineThickness( layer ) );
2087
2088 switch( seg->shape )
2089 {
2090
2091 case GR_SHAPE_LINE:
2092 {
2093 const GRAPHIC_LINE* lsrc = static_cast<const GRAPHIC_LINE*>( seg.get() );
2094
2095 FP_SHAPE* line = new FP_SHAPE( fp, SHAPE_T::SEGMENT );
2096
2097 if( src->mirror )
2098 {
2099 line->SetLayer( FlipLayer( layer ) );
2100 line->SetStart( wxPoint( lsrc->start_x, 2 * src->y - lsrc->start_y ) );
2101 line->SetEnd( wxPoint( lsrc->end_x, 2 * src->y - lsrc->end_y ) );
2102 }
2103 else
2104 {
2105 line->SetLayer( layer );
2106 line->SetStart( wxPoint( lsrc->start_x, lsrc->start_y ) );
2107 line->SetEnd( wxPoint( lsrc->end_x, lsrc->end_y ) );
2108 }
2109
2111 line->SetLocalCoord();
2112
2113 if( lsrc->width == 0 )
2114 line->SetStroke( defaultStroke );
2115
2116 fp->Add( line, ADD_MODE::APPEND );
2117 break;
2118 }
2119 case GR_SHAPE_CIRCLE:
2120 {
2121 const GRAPHIC_ARC* lsrc = static_cast<const GRAPHIC_ARC*>( seg.get() );
2122
2123 FP_SHAPE* circle = new FP_SHAPE( fp, SHAPE_T::CIRCLE );
2124
2125 circle->SetLayer( layer );
2126 circle->SetCenter( wxPoint( lsrc->center_x, lsrc->center_y ) );
2127 circle->SetEnd( wxPoint( lsrc->end_x, lsrc->end_y ) );
2128 circle->SetWidth( lsrc->width );
2129 circle->SetLocalCoord();
2130
2131 if( lsrc->width == 0 )
2132 circle->SetWidth( ds.GetLineThickness( circle->GetLayer() ) );
2133
2134 if( src->mirror )
2135 circle->Flip( circle->GetCenter(), false );
2136
2137 fp->Add( circle, ADD_MODE::APPEND );
2138 break;
2139 }
2140 case GR_SHAPE_ARC:
2141 {
2142 const GRAPHIC_ARC* lsrc = static_cast<const GRAPHIC_ARC*>( seg.get() );
2143
2144 FP_SHAPE* arc = new FP_SHAPE( fp, SHAPE_T::ARC );
2145
2146 arc->SetLayer( layer );
2147 arc->SetArcGeometry( lsrc->result.GetP0(),
2148 lsrc->result.GetArcMid(),
2149 lsrc->result.GetP1() );
2151 arc->SetLocalCoord();
2152
2153 if( lsrc->width == 0 )
2154 arc->SetStroke( defaultStroke );
2155
2156 if( src->mirror )
2157 arc->Flip( arc->GetCenter(), false );
2158
2159 fp->Add( arc, ADD_MODE::APPEND );
2160 break;
2161 }
2162 case GR_SHAPE_RECTANGLE:
2163 {
2164 const GRAPHIC_RECTANGLE *lsrc =
2165 static_cast<const GRAPHIC_RECTANGLE*>( seg.get() );
2166
2167 FP_SHAPE* rect = new FP_SHAPE( fp, SHAPE_T::RECT );
2168
2169 if( src->mirror )
2170 {
2171 rect->SetLayer( FlipLayer( layer ) );
2172 rect->SetStart( wxPoint( lsrc->start_x, 2 * src->y - lsrc->start_y ) );
2173 rect->SetEnd( wxPoint( lsrc->end_x, 2 * src->y - lsrc->end_y ) );
2174 }
2175 else
2176 {
2177 rect->SetLayer( layer );
2178 rect->SetStart( wxPoint( lsrc->start_x, lsrc->start_y ) );
2179 rect->SetEnd( wxPoint( lsrc->end_x, lsrc->end_y ) );
2180 }
2181
2182 rect->SetStroke( defaultStroke );
2183 rect->SetLocalCoord();
2184
2185 fp->Add( rect, ADD_MODE::APPEND );
2186 break;
2187 }
2188 case GR_SHAPE_TEXT:
2189 {
2190 const GRAPHIC_TEXT *lsrc =
2191 static_cast<const GRAPHIC_TEXT*>( seg.get() );
2192
2193 FP_TEXT* txt = new FP_TEXT( fp );
2194
2195 if( src->mirror )
2196 {
2197 txt->SetLayer( FlipLayer( layer ) );
2198 txt->SetTextPos( wxPoint( lsrc->start_x, 2 * src->y - ( lsrc->start_y - lsrc->height / 2 ) ) );
2199 }
2200 else
2201 {
2202 txt->SetLayer( layer );
2203 txt->SetTextPos( wxPoint( lsrc->start_x, lsrc->start_y - lsrc->height / 2 ) );
2204 }
2205
2206 txt->SetText( lsrc->text );
2207 txt->SetItalic( lsrc->ital );
2208 txt->SetTextThickness( lsrc->thickness );
2209 txt->SetTextHeight( lsrc->height );
2210 txt->SetTextWidth( lsrc->width );
2211 txt->SetHorizJustify( lsrc->orient );
2212 txt->SetLocalCoord();
2213
2214 // FABMASTER doesn't have visibility flags but layers that are not silk should be hidden
2215 // by default to prevent clutter.
2216 if( txt->GetLayer() != F_SilkS && txt->GetLayer() != B_SilkS )
2217 txt->SetVisible( false );
2218
2219 fp->Add( txt, ADD_MODE::APPEND );
2220 break;
2221 }
2222 default:
2223 continue;
2224 }
2225 }
2226 }
2227
2228 auto pin_it = pins.find( src->refdes );
2229
2230 if( pin_it != pins.end() )
2231 {
2232 for( auto& pin : pin_it->second )
2233 {
2234 auto pin_net_it = pin_nets.find( std::make_pair( pin->refdes, pin->pin_number ) );
2235 auto padstack = pads.find( pin->padstack );
2236 std::string netname = "";
2237
2238 if( pin_net_it != pin_nets.end() )
2239 netname = pin_net_it->second.name;
2240
2241 auto net_it = netinfo.find( netname );
2242
2243 std::unique_ptr<PAD> newpad = std::make_unique<PAD>( fp );
2244
2245 if( net_it != netinfo.end() )
2246 newpad->SetNet( net_it->second );
2247 else
2248 newpad->SetNetCode( 0 );
2249
2250 newpad->SetX( pin->pin_x );
2251
2252 if( src->mirror )
2253 newpad->SetY( 2 * src->y - pin->pin_y );
2254 else
2255 newpad->SetY( pin->pin_y );
2256
2257 newpad->SetNumber( pin->pin_number );
2258
2259 if( padstack == pads.end() )
2260 {
2261 wxLogError( _( "Unable to locate padstack %s in file %s\n" ),
2262 pin->padstack.c_str(), aBoard->GetFileName().wc_str() );
2263 continue;
2264 }
2265 else
2266 {
2267 auto& pad = padstack->second;
2268
2269 newpad->SetShape( pad.shape );
2270
2271 if( pad.shape == PAD_SHAPE::CUSTOM )
2272 {
2273 // Choose the smaller dimension to ensure the base pad
2274 // is fully hidden by the custom pad
2275 int pad_size = std::min( pad.width, pad.height );
2276
2277 newpad->SetSize( wxSize( pad_size / 2, pad_size / 2 ) );
2278
2279 std::string custom_name = pad.custom_name + "_" + pin->refdes + "_" + pin->pin_number;
2280 auto custom_it = pad_shapes.find( custom_name );
2281
2282 if( custom_it != pad_shapes.end() )
2283 {
2284
2285 SHAPE_POLY_SET poly_outline;
2286 int last_subseq = 0;
2287 int hole_idx = -1;
2288
2289 poly_outline.NewOutline();
2290
2291 // Custom pad shapes have a group of elements
2292 // that are a list of graphical polygons
2293 for( const auto& el : (*custom_it).second.elements )
2294 {
2295 // For now, we are only processing the custom pad for the top layer
2296 // TODO: Use full padstacks when implementing in KiCad
2297 PCB_LAYER_ID primary_layer = src->mirror ? B_Cu : F_Cu;
2298
2299 if( getLayer( ( *( el.second.begin() ) )->layer ) != primary_layer )
2300 continue;
2301
2302 for( const auto& seg : el.second )
2303 {
2304 if( seg->subseq > 0 || seg->subseq != last_subseq )
2305 {
2306 poly_outline.Polygon(0).back().SetClosed( true );
2307 hole_idx = poly_outline.AddHole( SHAPE_LINE_CHAIN{} );
2308 }
2309
2310 if( seg->shape == GR_SHAPE_LINE )
2311 {
2312 const GRAPHIC_LINE* src = static_cast<const GRAPHIC_LINE*>( seg.get() );
2313
2314 if( poly_outline.VertexCount( 0, hole_idx ) == 0 )
2315 poly_outline.Append( src->start_x, src->start_y, 0, hole_idx );
2316
2317 poly_outline.Append( src->end_x, src->end_y, 0, hole_idx );
2318 }
2319 else if( seg->shape == GR_SHAPE_ARC )
2320 {
2321 const GRAPHIC_ARC* src = static_cast<const GRAPHIC_ARC*>( seg.get() );
2322 SHAPE_LINE_CHAIN& chain = poly_outline.Hole( 0, hole_idx );
2323
2324 chain.Append( src->result );
2325 }
2326 }
2327 }
2328
2329 if( poly_outline.OutlineCount() < 1
2330 || poly_outline.Outline( 0 ).PointCount() < 3 )
2331 {
2332 wxLogError( _( "Invalid custom pad '%s'. Replacing with "
2333 "circular pad." ),
2334 custom_name.c_str() );
2335 newpad->SetShape( PAD_SHAPE::CIRCLE );
2336 }
2337 else
2338 {
2339 poly_outline.Fracture( SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
2340
2341 poly_outline.Move( -newpad->GetPosition() );
2342
2343 if( src->mirror )
2344 {
2345 poly_outline.Mirror( false, true, VECTOR2I( 0, ( pin->pin_y - src->y ) ) );
2346 poly_outline.Rotate( EDA_ANGLE( src->rotate - pin->rotation, DEGREES_T ) );
2347 }
2348 else
2349 {
2350 poly_outline.Rotate( EDA_ANGLE( -src->rotate + pin->rotation, DEGREES_T ) );
2351 }
2352
2353 newpad->AddPrimitivePoly( poly_outline, 0, true );
2354 }
2355
2356 SHAPE_POLY_SET mergedPolygon;
2357 newpad->MergePrimitivesAsPolygon( &mergedPolygon );
2358
2359 if( mergedPolygon.OutlineCount() > 1 )
2360 {
2361 wxLogError( _( "Invalid custom pad '%s'. Replacing with "
2362 "circular pad." ),
2363 custom_name.c_str() );
2364 newpad->SetShape( PAD_SHAPE::CIRCLE );
2365 }
2366 }
2367 else
2368 {
2369 wxLogError( _( "Could not find custom pad '%s'." ),
2370 custom_name.c_str() );
2371 }
2372 }
2373 else
2374 newpad->SetSize( wxSize( pad.width, pad.height ) );
2375
2376 if( pad.drill )
2377 {
2378 if( pad.plated )
2379 {
2380 newpad->SetAttribute( PAD_ATTRIB::PTH );
2381 newpad->SetLayerSet( PAD::PTHMask() );
2382 }
2383 else
2384 {
2385 newpad->SetAttribute( PAD_ATTRIB::NPTH );
2386 newpad->SetLayerSet( PAD::UnplatedHoleMask() );
2387 }
2388
2389 if( pad.drill_size_x == pad.drill_size_y )
2390 newpad->SetDrillShape( PAD_DRILL_SHAPE_CIRCLE );
2391 else
2392 newpad->SetDrillShape( PAD_DRILL_SHAPE_OBLONG );
2393
2394 newpad->SetDrillSize( wxSize( pad.drill_size_x, pad.drill_size_y ) );
2395 }
2396 else
2397 {
2398 newpad->SetAttribute( PAD_ATTRIB::SMD );
2399
2400 if( pad.top )
2401 newpad->SetLayerSet( PAD::SMDMask() );
2402 else if( pad.bottom )
2403 newpad->SetLayerSet( FlipLayerMask( PAD::SMDMask() ) );
2404 }
2405 }
2406
2407 newpad->SetLocalCoord();
2408
2409 if( src->mirror )
2410 newpad->SetOrientation( EDA_ANGLE( -src->rotate + pin->rotation, DEGREES_T ) );
2411 else
2412 newpad->SetOrientation( EDA_ANGLE( src->rotate - pin->rotation, DEGREES_T ) );
2413
2414 if( newpad->GetSizeX() > 0 || newpad->GetSizeY() > 0 )
2415 {
2416 fp->Add( newpad.release(), ADD_MODE::APPEND );
2417 }
2418 else
2419 {
2420 wxLogError( _( "Invalid zero-sized pad ignored in\nfile: %s" ),
2421 aBoard->GetFileName().wc_str() );
2422 }
2423 }
2424 }
2425
2426 if( src->mirror )
2427 {
2428 fp->SetOrientationDegrees( 180.0 - src->rotate );
2429 fp->Flip( fp->GetPosition(), true );
2430 }
2431
2432 aBoard->Add( fp, ADD_MODE::APPEND );
2433 }
2434 }
2435
2436 return true;
2437}
2438
2439
2441{
2442 LSET layer_set;
2443
2445 layer_set |= LSET::AllTechMask() | LSET::UserMask();
2446
2447 for( auto& layer : layers )
2448 {
2449 checkpoint();
2450
2451 if( layer.second.layerid >= PCBNEW_LAYER_ID_START )
2452 layer_set.set( layer.second.layerid );
2453 }
2454
2455 aBoard->SetEnabledLayers( layer_set );
2456
2457 for( auto& layer : layers )
2458 {
2459 if( layer.second.conductive )
2460 {
2461 aBoard->SetLayerName( static_cast<PCB_LAYER_ID>( layer.second.layerid ),
2462 layer.second.name );
2463 }
2464 }
2465
2466 return true;
2467}
2468
2469
2471{
2472 const NETNAMES_MAP& netinfo = aBoard->GetNetInfo().NetsByName();
2473 const auto& ds = aBoard->GetDesignSettings();
2474
2475 for( auto& via : vias )
2476 {
2477 checkpoint();
2478
2479 auto net_it = netinfo.find( via->net );
2480 auto padstack = pads.find( via->padstack );
2481
2482 PCB_VIA* new_via = new PCB_VIA( aBoard );
2483
2484 new_via->SetPosition( wxPoint( via->x, via->y ) );
2485
2486 if( net_it != netinfo.end() )
2487 new_via->SetNet( net_it->second );
2488
2489 if( padstack == pads.end() )
2490 {
2491 new_via->SetDrillDefault();
2492
2493 if( !ds.m_ViasDimensionsList.empty() )
2494 {
2495 new_via->SetWidth( ds.m_ViasDimensionsList[0].m_Diameter );
2496 new_via->SetDrill( ds.m_ViasDimensionsList[0].m_Drill );
2497 }
2498 else
2499 {
2500 new_via->SetDrillDefault();
2501 new_via->SetWidth( ds.m_ViasMinSize );
2502 }
2503 }
2504 else
2505 {
2506 new_via->SetDrill( padstack->second.drill_size_x );
2507 new_via->SetWidth( padstack->second.width );
2508 }
2509
2510 aBoard->Add( new_via, ADD_MODE::APPEND );
2511 }
2512
2513 return true;
2514}
2515
2516
2518{
2519 for( auto& net : netnames )
2520 {
2521 checkpoint();
2522
2523 NETINFO_ITEM *newnet = new NETINFO_ITEM( aBoard, net );
2524 aBoard->Add( newnet, ADD_MODE::APPEND );
2525 }
2526
2527 return true;
2528}
2529
2530
2531bool FABMASTER::loadEtch( BOARD* aBoard, const std::unique_ptr<FABMASTER::TRACE>& aLine)
2532{
2533 const NETNAMES_MAP& netinfo = aBoard->GetNetInfo().NetsByName();
2534 auto net_it = netinfo.find( aLine->netname );
2535
2536 int last_subseq = 0;
2537 ZONE* new_zone = nullptr;
2538
2539 for( const auto& seg : aLine->segment )
2540 {
2541 PCB_LAYER_ID layer = getLayer( seg->layer );
2542
2543 if( IsCopperLayer( layer ) )
2544 {
2545 if( seg->shape == GR_SHAPE_LINE )
2546 {
2547 const GRAPHIC_LINE* src = static_cast<const GRAPHIC_LINE*>( seg.get() );
2548
2549 PCB_TRACK* trk = new PCB_TRACK( aBoard );
2550
2551 trk->SetLayer( layer );
2552 trk->SetStart( wxPoint( src->start_x, src->start_y ) );
2553 trk->SetEnd( wxPoint( src->end_x, src->end_y ) );
2554 trk->SetWidth( src->width );
2555
2556 if( net_it != netinfo.end() )
2557 trk->SetNet( net_it->second );
2558
2559 aBoard->Add( trk, ADD_MODE::APPEND );
2560 }
2561 else if( seg->shape == GR_SHAPE_ARC )
2562 {
2563 const GRAPHIC_ARC* src = static_cast<const GRAPHIC_ARC*>( seg.get() );
2564
2565 PCB_ARC* trk = new PCB_ARC( aBoard, &src->result );
2566 trk->SetLayer( layer );
2567 trk->SetWidth( src->width );
2568
2569 if( net_it != netinfo.end() )
2570 trk->SetNet( net_it->second );
2571
2572 aBoard->Add( trk, ADD_MODE::APPEND );
2573 }
2574 }
2575 else
2576 {
2577 wxLogError( _( "Expecting etch data to be on copper layer. Row found on layer '%s'" ),
2578 seg->layer.c_str() );
2579 }
2580 }
2581
2582 return true;
2583}
2584
2585
2587{
2588 SHAPE_POLY_SET poly_outline;
2589 int last_subseq = 0;
2590 int hole_idx = -1;
2591
2592 poly_outline.NewOutline();
2593
2594 for( const auto& seg : aElement )
2595 {
2596 if( seg->subseq > 0 || seg->subseq != last_subseq )
2597 hole_idx = poly_outline.AddHole( SHAPE_LINE_CHAIN{} );
2598
2599 if( seg->shape == GR_SHAPE_LINE )
2600 {
2601 const GRAPHIC_LINE* src = static_cast<const GRAPHIC_LINE*>( seg.get() );
2602
2603 if( poly_outline.VertexCount( 0, hole_idx ) == 0 )
2604 poly_outline.Append( src->start_x, src->start_y, 0, hole_idx );
2605
2606 poly_outline.Append( src->end_x, src->end_y, 0, hole_idx );
2607 }
2608 else if( seg->shape == GR_SHAPE_ARC )
2609 {
2610 const GRAPHIC_ARC* src = static_cast<const GRAPHIC_ARC*>( seg.get() );
2611 SHAPE_LINE_CHAIN& chain = poly_outline.Hole( 0, hole_idx );
2612
2613 chain.Append( src->result );
2614 }
2615 }
2616
2617 poly_outline.Fracture( SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
2618 return poly_outline;
2619}
2620
2621
2622bool FABMASTER::loadPolygon( BOARD* aBoard, const std::unique_ptr<FABMASTER::TRACE>& aLine)
2623{
2624 if( aLine->segment.size() < 3 )
2625 return false;
2626
2627 PCB_LAYER_ID layer = Cmts_User;
2628
2629 auto new_layer = getLayer( aLine->layer );
2630
2631 if( IsPcbLayer( new_layer ) )
2632 layer = new_layer;
2633
2634 SHAPE_POLY_SET poly_outline = loadShapePolySet( aLine->segment );
2635
2636 if( poly_outline.OutlineCount() < 1 || poly_outline.COutline( 0 ).PointCount() < 3 )
2637 return false;
2638
2639 STROKE_PARAMS defaultStroke( aBoard->GetDesignSettings().GetLineThickness( layer ) );
2640 PCB_SHAPE* new_poly = new PCB_SHAPE( aBoard );
2641
2642 new_poly->SetShape( SHAPE_T::POLY );
2643 new_poly->SetLayer( layer );
2644
2645 // Polygons on the silk layer are filled but other layers are not/fill doesn't make sense
2646 if( layer == F_SilkS || layer == B_SilkS )
2647 {
2648 new_poly->SetFilled( true );
2649 new_poly->SetStroke( STROKE_PARAMS( 0 ) );
2650 }
2651 else
2652 {
2653 new_poly->SetStroke( STROKE_PARAMS( ( *( aLine->segment.begin() ) )->width,
2655
2656 if( new_poly->GetWidth() == 0 )
2657 new_poly->SetStroke( defaultStroke );
2658 }
2659
2660 new_poly->SetPolyShape( poly_outline );
2661 aBoard->Add( new_poly, ADD_MODE::APPEND );
2662
2663 return true;
2664
2665}
2666
2667
2668bool FABMASTER::loadZone( BOARD* aBoard, const std::unique_ptr<FABMASTER::TRACE>& aLine)
2669{
2670 if( aLine->segment.size() < 3 )
2671 return false;
2672
2673 int last_subseq = 0;
2674 int hole_idx = -1;
2675 SHAPE_POLY_SET* zone_outline = nullptr;
2676 ZONE* zone = nullptr;
2677
2678 const NETNAMES_MAP& netinfo = aBoard->GetNetInfo().NetsByName();
2679 auto net_it = netinfo.find( aLine->netname );
2680 PCB_LAYER_ID layer = Cmts_User;
2681 auto new_layer = getLayer( aLine->layer );
2682
2683 if( IsPcbLayer( new_layer ) )
2684 layer = new_layer;
2685
2686 zone = new ZONE( aBoard );
2687 zone_outline = new SHAPE_POLY_SET;
2688
2689 if( net_it != netinfo.end() )
2690 zone->SetNet( net_it->second );
2691
2692 if( aLine->layer == "ALL" )
2693 zone->SetLayerSet( aBoard->GetLayerSet() & LSET::AllCuMask() );
2694 else
2695 zone->SetLayer( layer );
2696
2697 zone->SetIsRuleArea( false );
2698 zone->SetDoNotAllowTracks( false );
2699 zone->SetDoNotAllowVias( false );
2700 zone->SetDoNotAllowPads( false );
2701 zone->SetDoNotAllowFootprints( false );
2702 zone->SetDoNotAllowCopperPour( false );
2703
2704 if( aLine->lclass == "ROUTE KEEPOUT")
2705 {
2706 zone->SetIsRuleArea( true );
2707 zone->SetDoNotAllowTracks( true );
2708 }
2709 else if( aLine->lclass == "VIA KEEPOUT")
2710 {
2711 zone->SetIsRuleArea( true );
2712 zone->SetDoNotAllowVias( true );
2713 }
2714 else
2715 {
2716 zone->SetAssignedPriority( 50 );
2717 }
2718
2719 zone->SetLocalClearance( 0 );
2721
2722 zone_outline->NewOutline();
2723
2724
2725 for( const auto& seg : aLine->segment )
2726 {
2727 if( seg->subseq > 0 && seg->subseq != last_subseq )
2728 {
2730 if( aLine->lclass == "BOUNDARY" )
2731 break;
2732
2733 hole_idx = zone_outline->AddHole( SHAPE_LINE_CHAIN{} );
2734 last_subseq = seg->subseq;
2735 last_subseq = seg->subseq;
2736 }
2737
2738 if( seg->shape == GR_SHAPE_LINE )
2739 {
2740 const GRAPHIC_LINE* src = static_cast<const GRAPHIC_LINE*>( seg.get() );
2741
2742 if( zone_outline->VertexCount( 0, hole_idx ) == 0 )
2743 zone_outline->Append( src->start_x, src->start_y, 0, hole_idx );
2744
2745 zone_outline->Append( src->end_x, src->end_y, 0, hole_idx );
2746 }
2747 else if( seg->shape == GR_SHAPE_ARC )
2748 {
2749 const GRAPHIC_ARC* src = static_cast<const GRAPHIC_ARC*>( seg.get() );
2750 zone_outline->Hole( 0, hole_idx ).Append( src->result );
2751 }
2752 }
2753
2754 if( zone_outline->Outline( 0 ).PointCount() >= 3 )
2755 {
2756 zone->SetOutline( zone_outline );
2757 aBoard->Add( zone, ADD_MODE::APPEND );
2758 }
2759 else
2760 {
2761 delete( zone_outline );
2762 delete( zone );
2763 }
2764
2765 return true;
2766}
2767
2768
2769bool FABMASTER::loadOutline( BOARD* aBoard, const std::unique_ptr<FABMASTER::TRACE>& aLine)
2770{
2771 PCB_LAYER_ID layer;
2772
2773 if( aLine->lclass == "BOARD GEOMETRY" )
2774 layer = Edge_Cuts;
2775 else if( aLine->lclass == "DRAWING FORMAT" )
2776 layer = Dwgs_User;
2777 else
2778 layer = Cmts_User;
2779
2780 STROKE_PARAMS defaultStroke( aBoard->GetDesignSettings().GetLineThickness( layer ) );
2781
2782 for( auto& seg : aLine->segment )
2783 {
2784 switch( seg->shape )
2785 {
2786
2787 case GR_SHAPE_LINE:
2788 {
2789 const GRAPHIC_LINE* src = static_cast<const GRAPHIC_LINE*>( seg.get() );
2790
2791 PCB_SHAPE* line = new PCB_SHAPE( aBoard, SHAPE_T::SEGMENT );
2792 line->SetLayer( layer );
2793 line->SetStart( wxPoint( src->start_x, src->start_y ) );
2794 line->SetEnd( wxPoint( src->end_x, src->end_y ) );
2796
2797 if( line->GetWidth() == 0 )
2798 line->SetStroke( defaultStroke );
2799
2800 aBoard->Add( line, ADD_MODE::APPEND );
2801 break;
2802 }
2803 case GR_SHAPE_CIRCLE:
2804 {
2805 const GRAPHIC_ARC* lsrc = static_cast<const GRAPHIC_ARC*>( seg.get() );
2806
2807 PCB_SHAPE* circle = new PCB_SHAPE( aBoard, SHAPE_T::CIRCLE );
2808
2809 circle->SetLayer( layer );
2810 circle->SetCenter( wxPoint( lsrc->center_x, lsrc->center_y ) );
2811 circle->SetEnd( wxPoint( lsrc->end_x, lsrc->end_y ) );
2812 circle->SetWidth( lsrc->width );
2813
2814 if( lsrc->width == 0 )
2815 circle->SetWidth( aBoard->GetDesignSettings().GetLineThickness( circle->GetLayer() ) );
2816
2817 aBoard->Add( circle, ADD_MODE::APPEND );
2818 break;
2819 }
2820 case GR_SHAPE_ARC:
2821 {
2822 const GRAPHIC_ARC* src = static_cast<const GRAPHIC_ARC*>( seg.get() );
2823
2824 PCB_SHAPE* arc = new PCB_SHAPE( aBoard, SHAPE_T::ARC );
2825 arc->SetLayer( layer );
2826 arc->SetArcGeometry( src->result.GetP0(),
2827 src->result.GetArcMid(),
2828 src->result.GetP1() );
2830
2831 if( arc->GetWidth() == 0 )
2832 arc->SetStroke( defaultStroke );
2833
2834 aBoard->Add( arc, ADD_MODE::APPEND );
2835 break;
2836 }
2837 case GR_SHAPE_RECTANGLE:
2838 {
2839 const GRAPHIC_RECTANGLE *src =
2840 static_cast<const GRAPHIC_RECTANGLE*>( seg.get() );
2841
2842 PCB_SHAPE* rect = new PCB_SHAPE( aBoard, SHAPE_T::RECT );
2843 rect->SetLayer( layer );
2844 rect->SetStart( wxPoint( src->start_x, src->start_y ) );
2845 rect->SetEnd( wxPoint( src->end_x, src->end_y ) );
2846 rect->SetStroke( defaultStroke );
2847
2848 aBoard->Add( rect, ADD_MODE::APPEND );
2849 break;
2850 }
2851 case GR_SHAPE_TEXT:
2852 {
2853 const GRAPHIC_TEXT *src = static_cast<const GRAPHIC_TEXT*>( seg.get() );
2854
2855 PCB_TEXT* txt = new PCB_TEXT( aBoard );
2856 txt->SetLayer( layer );
2857 txt->SetTextPos( wxPoint( src->start_x, src->start_y - src->height / 2 ) );
2858 txt->SetText( src->text );
2859 txt->SetItalic( src->ital );
2860 txt->SetTextThickness( src->thickness );
2861 txt->SetTextHeight( src->height );
2862 txt->SetTextWidth( src->width );
2863 txt->SetHorizJustify( src->orient );
2864
2865 aBoard->Add( txt, ADD_MODE::APPEND );
2866 break;
2867 }
2868 default:
2869 return false;
2870 }
2871 }
2872
2873 return true;
2874}
2875
2876
2878{
2879
2880 for( auto& geom : board_graphics )
2881 {
2882 checkpoint();
2883
2884 PCB_LAYER_ID layer;
2885
2886 // The pin numbers are not useful for us outside of the footprints
2887 if( geom.subclass == "PIN_NUMBER" )
2888 continue;
2889
2890 layer = getLayer( geom.subclass );
2891
2892 if( !IsPcbLayer( layer ) )
2893 layer = Cmts_User;
2894
2895 if( !geom.elements->empty() )
2896 {
2898 if( ( *( geom.elements->begin() ) )->width == 0 )
2899 {
2900 SHAPE_POLY_SET poly_outline = loadShapePolySet( *( geom.elements ) );
2901
2902 if( poly_outline.OutlineCount() < 1 || poly_outline.COutline( 0 ).PointCount() < 3 )
2903 continue;
2904
2905 PCB_SHAPE* new_poly = new PCB_SHAPE( aBoard, SHAPE_T::POLY );
2906 new_poly->SetLayer( layer );
2907 new_poly->SetPolyShape( poly_outline );
2908 new_poly->SetStroke( STROKE_PARAMS( 0 ) );
2909
2910 if( layer == F_SilkS || layer == B_SilkS )
2911 new_poly->SetFilled( true );
2912
2913 aBoard->Add( new_poly, ADD_MODE::APPEND );
2914 }
2915 }
2916
2917 for( auto& seg : *geom.elements )
2918 {
2919 switch( seg->shape )
2920 {
2921
2922 case GR_SHAPE_LINE:
2923 {
2924 const GRAPHIC_LINE* src = static_cast<const GRAPHIC_LINE*>( seg.get() );
2925
2926 PCB_SHAPE* line = new PCB_SHAPE( aBoard, SHAPE_T::SEGMENT );
2927 line->SetLayer( layer );
2928 line->SetStart( wxPoint( src->start_x, src->start_y ) );
2929 line->SetEnd( wxPoint( src->end_x, src->end_y ) );
2931
2932 aBoard->Add( line, ADD_MODE::APPEND );
2933 break;
2934 }
2935 case GR_SHAPE_CIRCLE:
2936 {
2937 const GRAPHIC_ARC* src = static_cast<const GRAPHIC_ARC*>( seg.get() );
2938
2939 PCB_SHAPE* circle = new PCB_SHAPE( aBoard, SHAPE_T::CIRCLE );
2940
2941 circle->SetLayer( layer );
2942 circle->SetCenter( wxPoint( src->center_x, src->center_y ) );
2943 circle->SetEnd( wxPoint( src->end_x, src->end_y ) );
2944 circle->SetWidth( src->width );
2945
2946 aBoard->Add( circle, ADD_MODE::APPEND );
2947 break;
2948 }
2949 case GR_SHAPE_ARC:
2950 {
2951 const GRAPHIC_ARC* src = static_cast<const GRAPHIC_ARC*>( seg.get() );
2952
2953 PCB_SHAPE* arc = new PCB_SHAPE( aBoard, SHAPE_T::ARC );
2954 arc->SetLayer( layer );
2955 arc->SetArcGeometry( src->result.GetP0(),
2956 src->result.GetArcMid(),
2957 src->result.GetP1() );
2959
2960 aBoard->Add( arc, ADD_MODE::APPEND );
2961 break;
2962 }
2963 case GR_SHAPE_RECTANGLE:
2964 {
2965 const GRAPHIC_RECTANGLE *src =
2966 static_cast<const GRAPHIC_RECTANGLE*>( seg.get() );
2967
2968 PCB_SHAPE* rect = new PCB_SHAPE( aBoard, SHAPE_T::RECT );
2969 rect->SetLayer( layer );
2970 rect->SetStart( wxPoint( src->start_x, src->start_y ) );
2971 rect->SetEnd( wxPoint( src->end_x, src->end_y ) );
2972 rect->SetStroke( STROKE_PARAMS( 0 ) );
2973 rect->SetFilled( true );
2974 aBoard->Add( rect, ADD_MODE::APPEND );
2975 break;
2976 }
2977 case GR_SHAPE_TEXT:
2978 {
2979 const GRAPHIC_TEXT *src =
2980 static_cast<const GRAPHIC_TEXT*>( seg.get() );
2981
2982 PCB_TEXT* txt = new PCB_TEXT( aBoard );
2983 txt->SetLayer( layer );
2984 txt->SetTextPos( wxPoint( src->start_x, src->start_y - src->height / 2 ) );
2985 txt->SetText( src->text );
2986 txt->SetItalic( src->ital );
2987 txt->SetTextThickness( src->thickness );
2988 txt->SetTextHeight( src->height );
2989 txt->SetTextWidth( src->width );
2990 txt->SetHorizJustify( src->orient );
2991 aBoard->Add( txt, ADD_MODE::APPEND );
2992 break;
2993 }
2994 default:
2995 return false;
2996 }
2997 }
2998 }
2999
3000 return true;
3001
3002}
3003
3004
3006{
3007 std::sort( aBoard->Zones().begin(), aBoard->Zones().end(),
3008 [&]( const ZONE* a, const ZONE* b )
3009 {
3010 if( a->GetLayer() == b->GetLayer() )
3011 return a->GetBoundingBox().GetArea() > b->GetBoundingBox().GetArea();
3012
3013 return a->GetLayer() < b->GetLayer();
3014 } );
3015
3017 unsigned int priority = 0;
3018
3019 for( ZONE* zone : aBoard->Zones() )
3020 {
3022 if( zone->GetIsRuleArea() )
3023 continue;
3024
3025 if( zone->GetLayer() != layer )
3026 {
3027 layer = zone->GetLayer();
3028 priority = 0;
3029 }
3030
3031 zone->SetAssignedPriority( priority );
3032 priority += 10;
3033 }
3034
3035 return true;
3036}
3037
3038
3039bool FABMASTER::LoadBoard( BOARD* aBoard, PROGRESS_REPORTER* aProgressReporter )
3040{
3041 aBoard->SetFileName( m_filename.GetFullPath() );
3042 m_progressReporter = aProgressReporter;
3043
3044 m_totalCount = netnames.size()
3045 + layers.size()
3046 + vias.size()
3047 + components.size()
3048 + zones.size()
3049 + board_graphics.size()
3050 + traces.size();
3051 m_doneCount = 0;
3052
3053 loadNets( aBoard );
3054 loadLayers( aBoard );
3055 loadVias( aBoard );
3056 loadFootprints( aBoard );
3057 loadZones( aBoard );
3058 loadGraphics( aBoard );
3059
3060 for( auto& track : traces )
3061 {
3062 checkpoint();
3063
3064 if( track->lclass == "ETCH" )
3065 loadEtch( aBoard, track);
3066 else if( track->layer == "OUTLINE" )
3067 loadOutline( aBoard, track );
3068 }
3069
3070 orderZones( aBoard );
3071
3072 return true;
3073}
const char * name
Definition: DXF_plotter.cpp:56
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
int GetLineThickness(PCB_LAYER_ID aLayer) const
Return the default graphic segment thickness from the layer class for the given layer.
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:180
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:214
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:185
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:265
const NETINFO_LIST & GetNetInfo() const
Definition: board.h:765
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: board.cpp:711
void SetFileName(const wxString &aFileName)
Definition: board.h:300
void SetEnabledLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:546
ZONES & Zones()
Definition: board.h:313
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Changes the name of the layer given by aLayer.
Definition: board.cpp:429
const wxString & GetFileName() const
Definition: board.h:302
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:643
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: board.cpp:820
bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:269
EDA_ANGLE Normalize()
Definition: eda_angle.h:249
void SetCenter(const VECTOR2I &aCenter)
Definition: eda_shape.cpp:458
void SetFilled(bool aFlag)
Definition: eda_shape.h:95
void SetPolyShape(const SHAPE_POLY_SET &aShape)
Definition: eda_shape.h:255
void SetStart(const VECTOR2I &aStart)
Definition: eda_shape.h:124
void SetShape(SHAPE_T aShape)
Definition: eda_shape.h:112
int GetWidth() const
Definition: eda_shape.h:109
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:149
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Set the three controlling points for an arc.
Definition: eda_shape.cpp:543
void SetWidth(int aWidth)
Definition: eda_shape.h:108
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:371
void SetTextWidth(int aWidth)
Definition: eda_text.cpp:355
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:217
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.cpp:185
void SetTextHeight(int aHeight)
Definition: eda_text.cpp:363
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:163
void SetItalic(bool aItalic)
Definition: eda_text.cpp:201
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition: eda_text.cpp:240
size_t processFootprints(size_t aRow)
A!REFDES!COMP_CLASS!COMP_PART_NUMBER!COMP_HEIGHT!COMP_DEVICE_LABEL!COMP_INSERTION_CODE!...
unsigned m_doneCount
size_t processPins(size_t aRow)
A!SYM_NAME!SYM_MIRROR!PIN_NAME!PIN_NUMBER!PIN_X!PIN_Y!PAD_STACK_NAME!REFDES!PIN_ROTATION!...
int readInt(const std::string &aStr) const
wxFileName m_filename
size_t processGeometry(size_t aRow)
A!GRAPHIC_DATA_NAME!GRAPHIC_DATA_NUMBER!RECORD_TAG!GRAPHIC_DATA_1!GRAPHIC_DATA_2!GRAPHIC_DATA_3!...
bool Read(const std::string &aFile)
bool loadNets(BOARD *aBoard)
std::map< std::string, std::map< int, GEOM_GRAPHIC > > comp_graphics
unsigned m_lastProgressCount
SYMTYPE parseSymType(const std::string &aSymType)
GRAPHIC_TEXT * processText(const GRAPHIC_DATA &aData, double aScale)
bool loadLayers(BOARD *aBoard)
PCB_LAYER_ID getLayer(const std::string &aLayerName)
bool loadZones(BOARD *aBoard)
Loads sections of the database into the board.
GRAPHIC_RECTANGLE * processRectangle(const GRAPHIC_DATA &aData, double aScale)
std::vector< std::string > single_row
size_t processSimpleLayers(size_t aRow)
PROGRESS_REPORTER * m_progressReporter
optional; may be nullptr
bool loadFootprints(BOARD *aBoard)
std::unordered_map< std::string, FM_PAD > pads
int getColFromName(size_t aRow, const std::string &aStr)
bool loadVias(BOARD *aBoard)
size_t processLayers(size_t aRow)
A!LAYER_SORT!LAYER_SUBCLASS!LAYER_ARTWORK!LAYER_USE!LAYER_CONDUCTOR!LAYER_DIELECTRIC_CONSTANT!...
std::map< std::string, FABMASTER_LAYER > layers
COMPCLASS parseCompClass(const std::string &aCompClass)
bool loadEtch(BOARD *aBoard, const std::unique_ptr< TRACE > &aLine)
std::map< std::string, std::set< std::unique_ptr< PIN >, PIN::BY_NUM > > pins
std::set< std::unique_ptr< GRAPHIC_ITEM >, GRAPHIC_ITEM::SEQ_CMP > graphic_element
std::map< std::pair< std::string, std::string >, NETNAME > pin_nets
GRAPHIC_ITEM * processGraphic(const GRAPHIC_DATA &aData, double aScale)
Specialty functions for processing graphical data rows into the internal database.
std::deque< single_row > rows
bool loadOutline(BOARD *aBoard, const std::unique_ptr< TRACE > &aLine)
size_t processPadStacks(size_t aRow)
A!PADNAME!RECNUMBER!LAYER!FIXFLAG!VIAFLAG!PADSHAPE1!PADWIDTH!PADHGHT! PADXOFF!PADYOFF!...
std::vector< GEOM_GRAPHIC > board_graphics
section_type detectType(size_t aOffset)
double readDouble(const std::string &aStr) const
Reads the double/integer value from a std string independent of the user locale.
bool loadZone(BOARD *aBoard, const std::unique_ptr< FABMASTER::TRACE > &aLine)
GRAPHIC_ARC * processArc(const GRAPHIC_DATA &aData, double aScale)
SHAPE_POLY_SET loadShapePolySet(const graphic_element &aLine)
bool loadGraphics(BOARD *aBoard)
std::unordered_map< std::string, FABMASTER_PAD_SHAPE > pad_shapes
bool LoadBoard(BOARD *aBoard, PROGRESS_REPORTER *aProgressReporter)
std::vector< std::unique_ptr< FM_VIA > > vias
std::set< std::unique_ptr< TRACE >, TRACE::BY_ID > traces
std::set< std::unique_ptr< TRACE >, TRACE::BY_ID > zones
std::map< std::string, std::vector< std::unique_ptr< COMPONENT > > > components
bool loadPolygon(BOARD *aBoard, const std::unique_ptr< FABMASTER::TRACE > &aLine)
std::set< std::unique_ptr< TRACE >, TRACE::BY_ID > refdes
@ GR_SHAPE_CIRCLE
! Not actually in Fabmaster but we use for 360° arcs
size_t processPadStackLayers(size_t aRow)
std::set< std::string > netnames
size_t processTraces(size_t aRow)
A!CLASS!SUBCLASS!GRAPHIC_DATA_NAME!GRAPHIC_DATA_NUMBER!RECORD_TAG!GRAPHIC_DATA_1!GRAPHIC_DATA_2!...
size_t processNets(size_t aRow)
A!NET_NAME!REFDES!PIN_NUMBER!PIN_NAME!PIN_GROUND!PIN_POWER!
@ FABMASTER_EXTRACT_PINS
bool orderZones(BOARD *aBoard)
Sets zone priorities based on zone BB size.
double processScaleFactor(size_t aRow)
Processes data from text vectors into internal database for further ordering.
size_t processVias(size_t aRow)
A!VIA_X!VIA_Y!PAD_STACK_NAME!NET_NAME!TEST_POINT!
unsigned m_totalCount
for progress reporting
size_t processCustomPads(size_t aRow)
A!SUBCLASS!PAD_SHAPE_NAME!GRAPHIC_DATA_NAME!GRAPHIC_DATA_NUMBER!RECORD_TAG!GRAPHIC_DATA_1!...
GRAPHIC_LINE * processLine(const GRAPHIC_DATA &aData, double aScale)
void SetPosition(const VECTOR2I &aPos) override
Definition: footprint.cpp:1658
void SetFPID(const LIB_ID &aFPID)
Definition: footprint.h:213
void SetOrientationDegrees(double aOrientation)
Definition: footprint.h:203
void SetReference(const wxString &aReference)
Definition: footprint.h:528
void SetValue(const wxString &aValue)
Definition: footprint.h:555
FP_TEXT & Value()
read/write accessors:
Definition: footprint.h:567
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: footprint.cpp:561
void Flip(const VECTOR2I &aCentre, bool aFlipLeftRight) override
Flip this object, i.e.
Definition: footprint.cpp:1574
VECTOR2I GetPosition() const override
Definition: footprint.h:188
FP_TEXT & Reference()
Definition: footprint.h:568
void Flip(const VECTOR2I &aCentre, bool aFlipLeftRight) override
Flip entity relative to aCentre.
Definition: fp_shape.cpp:219
virtual void SetLocalCoord()
Set relative coordinates from draw coordinates.
Definition: fp_shape.cpp:52
void SetLocalCoord()
Definition: fp_text.cpp:220
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:50
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:530
static LSET UserMask()
Definition: lset.cpp:855
static LSET AllTechMask()
Return a mask holding all technical layers (no CU layer) on both side.
Definition: lset.cpp:841
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:773
Handle the data for a net.
Definition: netinfo.h:66
unsigned GetNetCount() const
Definition: netinfo.h:347
const NETNAMES_MAP & NetsByName() const
Return the name map, at least for python.
Definition: netinfo.h:366
static LSET PTHMask()
layer set for a through hole pad
Definition: pad.cpp:179
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
Definition: pad.cpp:200
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition: pad.cpp:186
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_shape.h:67
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: pcb_shape.h:72
void SetWidth(int aWidth)
Definition: pcb_track.h:105
void SetEnd(const VECTOR2I &aEnd)
Definition: pcb_track.h:108
void SetStart(const VECTOR2I &aStart)
Definition: pcb_track.h:111
void SetDrillDefault()
Function SetDrillDefault sets the drill value for vias to the default value UNDEFINED_DRILL_DIAMETER.
Definition: pcb_track.h:533
void SetDrill(int aDrill)
Function SetDrill sets the drill value for vias.
Definition: pcb_track.h:512
void SetPosition(const VECTOR2I &aPoint) override
Definition: pcb_track.h:439
A progress reporter interface for use in multi-threaded environments.
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void SetCurrentProgress(double aProgress)=0
Set the progress value to aProgress (0..1).
const VECTOR2I & GetArcMid() const
Definition: shape_arc.h:114
const VECTOR2I & GetP1() const
Definition: shape_arc.h:113
const VECTOR2I & GetP0() const
Definition: shape_arc.h:112
bool PointOnEdge(const VECTOR2I &aP, int aAccuracy=0) const
Check if point aP lies on an edge or vertex of the line chain.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int PointCount() const
Return the number of points (vertices) in this line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const std::vector< VECTOR2I > & CPoints() const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
Represent a set of closed polygons.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
void Fracture(POLYGON_MODE aFastMode)
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
int VertexCount(int aOutline=-1, int aHole=-1) const
Return the number of points in the shape poly set.
POLYGON & Polygon(int aIndex)
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
int AddHole(const SHAPE_LINE_CHAIN &aHole, int aOutline=-1)
Return the area of this poly set.
void Mirror(bool aX=true, bool aY=false, const VECTOR2I &aRef={ 0, 0 })
Mirror the line points about y or x (or both)
SHAPE_LINE_CHAIN & Outline(int aIndex)
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Return the aIndex-th subpolygon in the set.
int NewOutline()
Creates a new hole in a given outline.
int OutlineCount() const
Return the number of vertices in a given outline/hole.
void Move(const VECTOR2I &aVector) override
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Simple container to manage line stroke parameters.
Definition: stroke_params.h:88
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
void SetDoNotAllowPads(bool aEnable)
Definition: zone.h:708
void SetDoNotAllowCopperPour(bool aEnable)
Definition: zone.h:705
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: zone.cpp:257
void SetIsRuleArea(bool aEnable)
Definition: zone.h:704
void SetDoNotAllowTracks(bool aEnable)
Definition: zone.h:707
void SetDoNotAllowVias(bool aEnable)
Definition: zone.h:706
void SetLocalClearance(int aClearance)
Definition: zone.h:153
void SetLayerSet(LSET aLayerSet) override
Definition: zone.cpp:263
void SetDoNotAllowFootprints(bool aEnable)
Definition: zone.h:709
void SetAssignedPriority(unsigned aPriority)
Definition: zone.h:107
void SetPadConnection(ZONE_CONNECTION aPadConnection)
Definition: zone.h:249
void SetOutline(SHAPE_POLY_SET *aOutline)
Definition: zone.h:315
The common library.
#define _(s)
@ DEGREES_T
Definition: eda_angle.h:31
static constexpr EDA_ANGLE & ANGLE_360
Definition: eda_angle.h:418
static constexpr EDA_ANGLE & ANGLE_0
Definition: eda_angle.h:412
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
bool IsPcbLayer(int aLayer)
Test whether a layer is a valid layer for Pcbnew.
Definition: layer_ids.h:814
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:825
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
@ PCBNEW_LAYER_ID_START
Definition: layer_ids.h:63
@ F_CrtYd
Definition: layer_ids.h:117
@ Edge_Cuts
Definition: layer_ids.h:113
@ Dwgs_User
Definition: layer_ids.h:109
@ F_Paste
Definition: layer_ids.h:101
@ Cmts_User
Definition: layer_ids.h:110
@ B_Mask
Definition: layer_ids.h:106
@ B_Cu
Definition: layer_ids.h:95
@ F_Mask
Definition: layer_ids.h:107
@ B_Paste
Definition: layer_ids.h:100
@ UNSELECTED_LAYER
Definition: layer_ids.h:61
@ F_Fab
Definition: layer_ids.h:120
@ F_SilkS
Definition: layer_ids.h:104
@ B_CrtYd
Definition: layer_ids.h:116
@ UNDEFINED_LAYER
Definition: layer_ids.h:60
@ B_SilkS
Definition: layer_ids.h:103
@ F_Cu
Definition: layer_ids.h:64
@ B_Fab
Definition: layer_ids.h:119
LSET FlipLayerMask(LSET aMask, int aCopperLayersCount)
Calculate the mask layer when flipping a footprint.
Definition: lset.cpp:590
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition: lset.cpp:544
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
void delete_if(_Container &__c, _Function &&__f)
Deletes all values from __c for which __f returns true.
Definition: kicad_algo.h:173
@ NPTH
like PAD_PTH, but not plated
@ SMD
Smd pad, appears on the solder paste layer (default)
@ PTH
Plated through hole pad.
@ PAD_DRILL_SHAPE_CIRCLE
Definition: pad_shapes.h:70
@ PAD_DRILL_SHAPE_OBLONG
Definition: pad_shapes.h:71
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
bool ReplaceIllegalFileNameChars(std::string *aName, int aReplaceChar)
Checks aName for illegal file name characters.
static std::vector< std::string > split(const std::string &aStr, const std::string &aDelim)
Split the input string into a vector of output strings.
Definition: string_utils.h:296
const double IU_PER_MM
Definition: base_units.h:77
const double IU_PER_MILS
Definition: base_units.h:78
A!LAYER_SORT!LAYER_SUBCLASS!LAYER_ARTWORK!LAYER_USE!LAYER_CONDUCTOR!LAYER_DIELECTRIC_CONSTANT !...
bool disable
! if true, prevent the layer elements from being used
std::string name
! LAYER_SUBCLASS
int layerid
! pcbnew layer (assigned)
bool conductive
! LAYER_CONDUCTOR
bool positive
! LAYER_ARTWORK (either POSITIVE or NEGATIVE)
A!SUBCLASS!PAD_SHAPE_NAME!GRAPHIC_DATA_NAME!GRAPHIC_DATA_NUMBER!RECORD_TAG!GRAPHIC_DATA_1!...
std::string name
! SYM_NAME
std::string refdes
! REFDES
std::string subclass
! SUBCLASS
int id
! RECORD_TAG[0]
std::unique_ptr< graphic_element > elements
int end_x
! GRAPHIC_DATA_3
SHAPE_ARC result
! KiCad-style arc representation
int radius
! GRAPHIC_DATA_7 ! width is GRAPHIC_DATA_8
int center_x
! GRAPHIC_DATA_5
bool clockwise
! GRAPHIC_DATA_9
int center_y
! GRAPHIC_DATA_6
int end_y
! GRAPHIC_DATA_4
int width
! Various sections depending on type
GRAPHIC_SHAPE shape
! Shape of the graphic_item
int start_y
! GRAPHIC_DATA_2
int start_x
! GRAPHIC_DATA_1
GRAPHIC_TYPE type
! Type of graphic item
int end_x
! GRAPHIC_DATA_3
int end_y
! GRAPHIC_DATA_4 ! width is GRAPHIC_DATA_5
double rotation
! GRAPHIC_DATA_3
std::string text
! GRAPHIC_DATA_7
int height
! GRAPHIC_DATA_6[2]
int thickness
! GRAPHIC_DATA_6[6]
GR_TEXT_H_ALIGN_T orient
! GRAPHIC_DATA_5
bool ital
! GRAPHIC_DATA_6[4] != 0.0
bool mirror
! GRAPHIC_DATA_4
std::string refdes
!< NET_NAME
bool pin_pwr
!< PIN_GND
std::string pin_num
!< REFDES
std::string pin_name
!< PIN_NUMBER
bool pin_gnd
!< PIN_NAME
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Definition: trigo.cpp:183
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618
@ FULL
pads are covered by copper