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