KiCad PCB EDA Suite
Loading...
Searching...
No Matches
gerber_jobfile_writer.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) 2018 Jean_Pierre Charras <jp.charras at wanadoo.fr>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
25
26#include <fstream>
27#include <iomanip>
28#include <vector>
29
30#include <build_version.h>
31#include <common.h>
32#include <locale_io.h>
33#include <pcb_edit_frame.h>
34#include <plotters/plotter.h>
35
36#include <board.h>
39#include <footprint.h>
40#include <pad.h>
41#include <pcb_track.h>
42#include <zone.h>
43
45#include <gbr_metadata.h>
47#include <pcbplot.h>
48#include <reporter.h>
50
51
53{
54 m_pcb = aPcb;
55 m_reporter = aReporter;
56 m_conversionUnits = 1.0 / pcbIUScale.IU_PER_MM; // Gerber units = mm
57}
58
59std::string GERBER_JOBFILE_WRITER::formatStringFromUTF32( const wxString& aText )
60{
61 std::string fmt_text; // the text after UTF32 to UTF8 conversion
62 fmt_text = aText.utf8_string();
63
64 return fmt_text;
65}
66
67
69{
70 int flag = SIDE_NONE;
71
72 for( PCB_LAYER_ID layer : m_params.m_LayerId )
73 {
74 if( layer == B_SilkS )
76
77 if( layer == F_SilkS )
78 flag |= SIDE_TOP;
79 }
80
81 return (enum ONSIDE) flag;
82}
83
84
86{
87 int flag = SIDE_NONE;
88
89 for( PCB_LAYER_ID layer : m_params.m_LayerId )
90 {
91 if( layer == B_Mask )
93
94 if( layer == F_Mask )
95 flag |= SIDE_TOP;
96 }
97
98 return (enum ONSIDE) flag;
99}
100
102{
103 // return the key associated to sides used for some layers
104 // "No, TopOnly, BotOnly or Both"
105 const char* value = nullptr;
106
107 switch( aValue )
108 {
109 case SIDE_NONE: value = "No"; break;
110 case SIDE_TOP: value = "TopOnly"; break;
111 case SIDE_BOTTOM: value = "BotOnly"; break;
112 case SIDE_BOTH: value = "Both"; break;
113 }
114
115 return value;
116}
117
118
119bool GERBER_JOBFILE_WRITER::CreateJobFile( const wxString& aFullFilename )
120{
121 bool success;
122 wxString msg;
123
124 success = WriteJSONJobFile( aFullFilename );
125
126 if( !success )
127 {
128 if( m_reporter )
129 {
130 msg.Printf( _( "Failed to create file '%s'." ), aFullFilename );
131 m_reporter->Report( msg, RPT_SEVERITY_ERROR );
132 }
133 }
134 else if( m_reporter )
135 {
136 msg.Printf( _( "Created Gerber job file '%s'." ), aFullFilename );
137 m_reporter->Report( msg, RPT_SEVERITY_ACTION );
138 }
139
140 return success;
141}
142
143
145{
146 m_json["Header"] = {
147 {
148 "GenerationSoftware",
149 {
150 { "Vendor", "KiCad" },
151 { "Application", "Pcbnew" },
152 { "Version", GetBuildVersion() }
153 }
154 },
155 {
156 // The attribute value must conform to the full version of the ISO 8601
157 // date and time format, including time and time zone.
159 }
160 };
161}
162
163
164bool GERBER_JOBFILE_WRITER::WriteJSONJobFile( const wxString& aFullFilename )
165{
166 // Note: in Gerber job file, dimensions are in mm, and are floating numbers
167 std::ofstream file( aFullFilename.ToUTF8() );
168
169 m_json = nlohmann::ordered_json( {} );
170
171 // output the job file header
173
174 // Add the General Specs
176
177 // Job file support a few design rules:
179
180 // output the gerber file list:
182
183 // output the board stackup:
185
186 file << std::setw( 2 ) << m_json << std::endl;
187
188 return true;
189}
190
191
192double GERBER_JOBFILE_WRITER::mapValue( double aUiValue )
193{
194 // A helper function to convert aUiValue in Json units (mm) and to have
195 // 4 digits in Json in mantissa when using %g to print it
196 // i.e. displays values truncated in 0.1 microns.
197 // This is enough for a Json file
198 char buffer[128];
199 std::snprintf( buffer, sizeof( buffer ), "%.4f", aUiValue * m_conversionUnits );
200
201 long double output;
202 sscanf( buffer, "%Lg", &output );
203
204 return output;
205
206}
207
208
210{
211 m_json["GeneralSpecs"] = nlohmann::ordered_json( {} );
212 m_json["GeneralSpecs"]["ProjectId"] = nlohmann::ordered_json( {} );
213
214 // Creates the ProjectId. Format is (from Gerber file format doc):
215 // ProjectId,<project id>,<project GUID>,<revision id>*%
216 // <project id> is the name of the project, restricted to basic ASCII symbols only,
217 // and comma not accepted
218 // All illegal chars will be replaced by underscore
219 // Rem: <project id> accepts only ASCII 7 code (only basic ASCII codes are allowed in gerber files).
220 //
221 // <project GUID> is a string which is an unique id of a project.
222 // However Kicad does not handle such a project GUID, so it is built from the board name
223 wxFileName fn = m_pcb->GetFileName();
224 wxString msg = fn.GetFullName();
225
226 // Build a <project GUID>, from the board name
227 wxString guid = GbrMakeProjectGUIDfromString( msg );
228
229 // build the <project id> string: this is the board short filename (without ext)
230 // and in UTF8 format.
231 msg = fn.GetName();
232
233 // build the <rev> string. All non ASCII chars are in UTF8 form
234 wxString rev = ExpandTextVars( m_pcb->GetTitleBlock().GetRevision(), m_pcb->GetProject() );
235
236 if( rev.IsEmpty() )
237 rev = wxT( "rev?" );
238
239 m_json["GeneralSpecs"]["ProjectId"]["Name"] = msg.utf8_string().c_str();
240 m_json["GeneralSpecs"]["ProjectId"]["GUID"] = guid;
241 m_json["GeneralSpecs"]["ProjectId"]["Revision"] = rev.utf8_string().c_str();
242
243 // output the board size in mm:
244 BOX2I brect = m_pcb->GetBoardEdgesBoundingBox();
245
246 m_json["GeneralSpecs"]["Size"]["X"] = mapValue( brect.GetWidth() );
247 m_json["GeneralSpecs"]["Size"]["Y"] = mapValue( brect.GetHeight() );
248
249
250 // Add some data to the JSON header, GeneralSpecs:
251 // number of copper layers
252 m_json["GeneralSpecs"]["LayerNumber"] = m_pcb->GetCopperLayerCount();
253
254 // Board thickness
255 m_json["GeneralSpecs"]["BoardThickness"] =
256 mapValue( m_pcb->GetDesignSettings().GetBoardThickness() );
257
258 // Copper finish
259 const BOARD_STACKUP brd_stackup = m_pcb->GetDesignSettings().GetStackupDescriptor();
260
261 if( !brd_stackup.m_FinishType.IsEmpty() )
262 m_json["GeneralSpecs"]["Finish"] = brd_stackup.m_FinishType;
263
264 if( brd_stackup.m_HasDielectricConstrains )
265 m_json["GeneralSpecs"]["ImpedanceControlled"] = true;
266
267 #if 0 // Old way to set property
268 if( brd_stackup.m_CastellatedPads )
269 m_json["GeneralSpecs"]["Castellated"] = true;
270 #endif
271 if( m_pcb->GetPadWithCastellatedAttrCount() )
272 m_json["GeneralSpecs"]["Castellated"] = true;
273
274 if( m_pcb->GetPadWithPressFitAttrCount() )
275 m_json["GeneralSpecs"]["Press-fit"] = true;
276
277 if( brd_stackup.m_EdgePlating )
278 m_json["GeneralSpecs"]["EdgePlating"] = true;
279
280 if( brd_stackup.m_EdgeConnectorConstraints )
281 {
282 m_json["GeneralSpecs"]["EdgeConnector"] = true;
283
284 m_json["GeneralSpecs"]["EdgeConnectorBevelled"] =
286 }
287
288#if 0 // Not yet in use
289 /* The board type according to IPC-2221. There are six primary board types:
290 - Type 1 - Single-sided
291 - Type 2 - Double-sided
292 - Type 3 - Multilayer, TH components only
293 - Type 4 - Multilayer, with TH, blind and/or buried vias.
294 - Type 5 - Multilayer metal-core board, TH components only
295 - Type 6 - Multilayer metal-core
296 */
297 m_json["GeneralSpecs"]["IPC-2221-Type"] = 4;
298
299 /* Via protection: key words:
300 Ia Tented - Single-sided
301 Ib Tented - Double-sided
302 IIa Tented and Covered - Single-sided
303 IIb Tented and Covered - Double-sided
304 IIIa Plugged - Single-sided
305 IIIb Plugged - Double-sided
306 IVa Plugged and Covered - Single-sided
307 IVb Plugged and Covered - Double-sided
308 V Filled (fully plugged)
309 VI Filled and Covered
310 VIII Filled and Capped
311 None...No protection
312 */
313 m_json["GeneralSpecs"]["ViaProtection"] = "Ib";
314#endif
315}
316
317
319{
320 // Add the Files Attributes section in JSON format to m_JSONbuffer
321 m_json["FilesAttributes"] = nlohmann::ordered_json::array();
322
323 for( unsigned ii = 0; ii < m_params.m_GerberFileList.GetCount(); ii++ )
324 {
325 wxString& name = m_params.m_GerberFileList[ii];
326 PCB_LAYER_ID layer = m_params.m_LayerId[ii];
327 wxString gbr_layer_id;
328 bool skip_file = false; // true to skip files which should not be in job file
329 const char* polarity = "Positive";
330
331 nlohmann::ordered_json file_json;
332
333 if( IsCopperLayer( layer ) )
334 {
335 gbr_layer_id = wxT( "Copper,L" );
336
337 if( layer == B_Cu )
338 gbr_layer_id << m_pcb->GetCopperLayerCount();
339 else if( layer == F_Cu )
340 gbr_layer_id << 1;
341 else // Copper layers are numbered B_Cu + n*2 for inner layer n (n = 1 ... val max)
342 // and gbr_layer_id = 2 ... val max
343 gbr_layer_id << (layer-B_Cu) / 2 + 1;
344
345 gbr_layer_id << wxT( "," );
346
347 if( layer == B_Cu )
348 gbr_layer_id << wxT( "Bot" );
349 else if( layer == F_Cu )
350 gbr_layer_id << wxT( "Top" );
351 else
352 gbr_layer_id << wxT( "Inr" );
353 }
354
355 else if( IsUserLayer( layer ) )
356 {
357 gbr_layer_id = wxT( "Other,User" );
358 }
359
360 else
361 {
362 switch( layer )
363 {
364 case B_Adhes:
365 gbr_layer_id = wxT( "Glue,Bot" );
366 break;
367 case F_Adhes:
368 gbr_layer_id = wxT( "Glue,Top" );
369 break;
370
371 case B_Paste:
372 gbr_layer_id = wxT( "SolderPaste,Bot" );
373 break;
374 case F_Paste:
375 gbr_layer_id = wxT( "SolderPaste,Top" );
376 break;
377
378 case B_SilkS:
379 gbr_layer_id = wxT( "Legend,Bot" );
380 break;
381 case F_SilkS:
382 gbr_layer_id = wxT( "Legend,Top" );
383 break;
384
385 case B_Mask:
386 gbr_layer_id = wxT( "SolderMask,Bot" );
387 polarity = "Negative";
388 break;
389 case F_Mask:
390 gbr_layer_id = wxT( "SolderMask,Top" );
391 polarity = "Negative";
392 break;
393
394 case Edge_Cuts:
395 gbr_layer_id = wxT( "Profile" );
396 break;
397
398 case B_Fab:
399 gbr_layer_id = wxT( "AssemblyDrawing,Bot" );
400 break;
401 case F_Fab:
402 gbr_layer_id = wxT( "AssemblyDrawing,Top" );
403 break;
404
405 case Margin:
406 case B_CrtYd:
407 case F_CrtYd:
408 skip_file = true;
409 break;
410
411 default:
412 skip_file = true;
413
414 if( m_reporter )
415 m_reporter->Report( wxT( "Unexpected layer id in job file" ), RPT_SEVERITY_ERROR );
416
417 break;
418 }
419 }
420
421 if( !skip_file )
422 {
423 // name can contain non ASCII7 chars.
424 // Ensure the name is JSON compatible.
425 std::string strname = formatStringFromUTF32( name );
426
427 file_json["Path"] = strname.c_str();
428 file_json["FileFunction"] = gbr_layer_id;
429 file_json["FilePolarity"] = polarity;
430
431 m_json["FilesAttributes"] += file_json;
432 }
433 }
434}
435
436
438{
439 // Add the Design Rules section in JSON format to m_JSONbuffer
440 // Job file support a few design rules:
441 std::shared_ptr<NET_SETTINGS>& netSettings = m_pcb->GetDesignSettings().m_NetSettings;
442
443 int minclearanceOuter = netSettings->GetDefaultNetclass()->GetClearance();
444 bool hasInnerLayers = m_pcb->GetCopperLayerCount() > 2;
445
446 // Search a smaller clearance in other net classes, if any.
447 for( const auto& [name, netclass] : netSettings->GetNetclasses() )
448 minclearanceOuter = std::min( minclearanceOuter, netclass->GetClearance() );
449
450 // job file knows different clearance types.
451 // Kicad knows only one clearance for pads and tracks
452 int minclearance_track2track = minclearanceOuter;
453
454 // However, pads can have a specific clearance defined for a pad or a footprint,
455 // and min clearance can be dependent on layers.
456 // Search for a minimal pad clearance:
457 int minPadClearanceOuter = netSettings->GetDefaultNetclass()->GetClearance();
458 int minPadClearanceInner = netSettings->GetDefaultNetclass()->GetClearance();
459
460 for( FOOTPRINT* footprint : m_pcb->Footprints() )
461 {
462 for( PAD* pad : footprint->Pads() )
463 {
464 for( PCB_LAYER_ID layer : pad->GetLayerSet() )
465 {
466 int padClearance = pad->GetOwnClearance( layer );
467
468 if( layer == B_Cu || layer == F_Cu )
469 minPadClearanceOuter = std::min( minPadClearanceOuter, padClearance );
470 else
471 minPadClearanceInner = std::min( minPadClearanceInner, padClearance );
472 }
473 }
474 }
475
476 m_json["DesignRules"] = { {
477 { "Layers", "Outer" },
478 { "PadToPad", mapValue( minPadClearanceOuter ) },
479 { "PadToTrack", mapValue( minPadClearanceOuter ) },
480 { "TrackToTrack", mapValue( minclearance_track2track ) }
481 } };
482
483 // Until this is changed in Kicad, use the same value for internal tracks
484 int minclearanceInner = minclearanceOuter;
485
486 // Output the minimal track width
487 int mintrackWidthOuter = INT_MAX;
488 int mintrackWidthInner = INT_MAX;
489
490 for( PCB_TRACK* track : m_pcb->Tracks() )
491 {
492 if( track->Type() == PCB_VIA_T )
493 continue;
494
495 if( track->GetLayer() == B_Cu || track->GetLayer() == F_Cu )
496 mintrackWidthOuter = std::min( mintrackWidthOuter, track->GetWidth() );
497 else
498 mintrackWidthInner = std::min( mintrackWidthInner, track->GetWidth() );
499 }
500
501 if( mintrackWidthOuter != INT_MAX )
502 m_json["DesignRules"][0]["MinLineWidth"] = mapValue( mintrackWidthOuter );
503
504 // Output the minimal zone to xx clearance
505 // Note: zones can have a zone clearance set to 0
506 // if happens, the actual zone clearance is the clearance of its class
507 minclearanceOuter = INT_MAX;
508 minclearanceInner = INT_MAX;
509
510 for( ZONE* zone : m_pcb->Zones() )
511 {
512 if( zone->GetIsRuleArea() || !zone->IsOnCopperLayer() )
513 continue;
514
515 for( PCB_LAYER_ID layer : zone->GetLayerSet() )
516 {
517 int zclerance = zone->GetOwnClearance( layer );
518
519 if( layer == B_Cu || layer == F_Cu )
520 minclearanceOuter = std::min( minclearanceOuter, zclerance );
521 else
522 minclearanceInner = std::min( minclearanceInner, zclerance );
523 }
524 }
525
526 if( minclearanceOuter != INT_MAX )
527 m_json["DesignRules"][0]["TrackToRegion"] = mapValue( minclearanceOuter );
528
529 if( minclearanceOuter != INT_MAX )
530 m_json["DesignRules"][0]["RegionToRegion"] = mapValue( minclearanceOuter );
531
532 if( hasInnerLayers )
533 {
534 m_json["DesignRules"] += nlohmann::ordered_json( {
535 { "Layers", "Inner" },
536 { "PadToPad", mapValue( minPadClearanceInner ) },
537 { "PadToTrack", mapValue( minPadClearanceInner ) },
538 { "TrackToTrack", mapValue( minclearance_track2track ) }
539 } );
540
541 if( mintrackWidthInner != INT_MAX )
542 m_json["DesignRules"][1]["MinLineWidth"] = mapValue( mintrackWidthInner );
543
544 if( minclearanceInner != INT_MAX )
545 m_json["DesignRules"][1]["TrackToRegion"] = mapValue( minclearanceInner );
546
547 if( minclearanceInner != INT_MAX )
548 m_json["DesignRules"][1]["RegionToRegion"] = mapValue( minclearanceInner );
549 }
550}
551
552
554{
555 // Add the Material Stackup section in JSON format to m_JSONbuffer
556 m_json["MaterialStackup"] = nlohmann::ordered_json::array();
557
558 // Build the candidates list:
559 LSET maskLayer;
560 BOARD_STACKUP brd_stackup = m_pcb->GetDesignSettings().GetStackupDescriptor();
561
562 // Ensure brd_stackup is up to date (i.e. no change made by SynchronizeWithBoard() )
563 bool uptodate = not brd_stackup.SynchronizeWithBoard( &m_pcb->GetDesignSettings() );
564
565 if( m_reporter && !uptodate && m_pcb->GetDesignSettings().m_HasStackup )
566 m_reporter->Report( _( "Board stackup settings not up to date." ), RPT_SEVERITY_ERROR );
567
568 PCB_LAYER_ID last_copper_layer = F_Cu;
569
570 // Generate the list (top to bottom):
571 for( int ii = 0; ii < brd_stackup.GetCount(); ++ii )
572 {
573 BOARD_STACKUP_ITEM* item = brd_stackup.GetStackupLayer( ii );
574
575 int sub_layer_count =
576 item->GetType() == BS_ITEM_TYPE_DIELECTRIC ? item->GetSublayersCount() : 1;
577
578 for( int sub_idx = 0; sub_idx < sub_layer_count; sub_idx++ )
579 {
580 // layer thickness is always in mm
581 double thickness = mapValue( item->GetThickness( sub_idx ) );
582 wxString layer_type;
583 std::string layer_name; // for comment
584
585 nlohmann::ordered_json layer_json;
586
587 switch( item->GetType() )
588 {
590 layer_type = wxT( "Copper" );
591 layer_name = formatStringFromUTF32( m_pcb->GetLayerName( item->GetBrdLayerId() ) );
592 last_copper_layer = item->GetBrdLayerId();
593 break;
594
596 layer_type = wxT( "Legend" );
597 layer_name = formatStringFromUTF32( item->GetTypeName() );
598 break;
599
601 layer_type = wxT( "SolderMask" );
602 layer_name = formatStringFromUTF32( item->GetTypeName() );
603 break;
604
606 layer_type = wxT( "SolderPaste" );
607 layer_name = formatStringFromUTF32( item->GetTypeName() );
608 break;
609
611 layer_type = wxT( "Dielectric" );
612 // The option core or prepreg is not added here, as it creates constraints
613 // in build process, not necessary wanted.
614 if( sub_layer_count > 1 )
615 {
616 layer_name =
617 formatStringFromUTF32( wxString::Format( wxT( "dielectric layer %d - %d/%d" ),
618 item->GetDielectricLayerId(), sub_idx + 1, sub_layer_count ) );
619 }
620 else
621 layer_name = formatStringFromUTF32( wxString::Format(
622 wxT( "dielectric layer %d" ), item->GetDielectricLayerId() ) );
623 break;
624
625 default:
626 break;
627 }
628
629 layer_json["Type"] = layer_type;
630
631 if( item->IsColorEditable() && uptodate )
632 {
633 if( IsPrmSpecified( item->GetColor( sub_idx ) ) )
634 {
635 wxString colorName = item->GetColor( sub_idx );
636
637 if( colorName.StartsWith( wxT( "#" ) ) ) // This is a user defined color,
638 // not in standard color list.
639 {
640 // In job file a color can be given by its RGB values (0...255)
641 // like R<number><G<number>B<number> notation
642 wxColor color( COLOR4D( colorName ).ToColour() );
643 colorName.Printf( wxT( "R%dG%dB%d" ),
644 color.Red(),
645 color.Green(),
646 color.Blue() );
647 }
648 else
649 {
650 const std::vector<FAB_LAYER_COLOR>& color_list =
651 GetStandardColors( item->GetType() );
652
653 // Colors for dielectric use a color list that is mainly not normalized in
654 // job file names. So if a color is in the dielectric standard color list
655 // it can be a standard name or not.
656 // Colors for solder mask and silk screen use a mainly normalized
657 // color list, but this list can also contain not normalized colors.
658 // If not normalized, use the R<number><G<number>B<number> notation
659 for( const FAB_LAYER_COLOR& prm_color : color_list )
660 {
661 if( colorName == prm_color.GetName() )
662 {
663 colorName = prm_color.GetColorAsString();
664 break;
665 }
666 }
667 }
668
669 layer_json["Color"] = colorName;
670 }
671 }
672
673 if( item->IsThicknessEditable() && uptodate )
674 layer_json["Thickness"] = thickness;
675
676 if( item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
677 {
678 if( item->HasMaterialValue() )
679 {
680 layer_json["Material"] = item->GetMaterial( sub_idx );
681
682 // These constrains are only written if the board has impedance controlled tracks.
683 // If the board is not impedance controlled, they are useless.
684 // Do not add constrains that create more expensive boards.
685
686 if( brd_stackup.m_HasDielectricConstrains )
687 {
688 // Generate Epsilon R if > 1.0 (value <= 1.0 means not specified: it is not
689 // a possible value
690 if( item->GetEpsilonR() > 1.0 )
691 layer_json["DielectricConstant"] = item->FormatEpsilonR( sub_idx );
692
693 // Generate LossTangent > 0.0 (value <= 0.0 means not specified: it is not
694 // a possible value
695 if( item->GetLossTangent() > 0.0 )
696 layer_json["LossTangent"] = item->FormatLossTangent( sub_idx );
697 }
698 }
699
700 // Copper layers IDs use only even values like 0, 2, 4 ...
701 // and first layer = F_Cu = 0, last layer = B_Cu = 2
702 // inner layers Ids are 4, 6 , 8 ...
703 PCB_LAYER_ID next_copper_layer = ( PCB_LAYER_ID )( last_copper_layer + 2 );
704
705 if( last_copper_layer == F_Cu )
706 next_copper_layer = In1_Cu;
707
708 // If the next_copper_layer is the last copper layer, the next layer id is B_Cu
709 if( next_copper_layer/2 >= m_pcb->GetCopperLayerCount() )
710 next_copper_layer = B_Cu;
711
712 wxString subLayerName;
713
714 if( sub_layer_count > 1 )
715 subLayerName.Printf( wxT( " (%d/%d)" ), sub_idx + 1, sub_layer_count );
716
717 wxString name = wxString::Format( wxT( "%s/%s%s" ),
718 formatStringFromUTF32( m_pcb->GetLayerName( last_copper_layer ) ),
719 formatStringFromUTF32( m_pcb->GetLayerName( next_copper_layer ) ),
720 subLayerName );
721
722 layer_json["Name"] = name;
723
724 // Add a comment ("Notes"):
725 wxString note;
726
727 note << wxString::Format( wxT( "Type: %s" ), layer_name.c_str() );
728
729 note << wxString::Format( wxT( " (from %s to %s)" ),
730 formatStringFromUTF32( m_pcb->GetLayerName( last_copper_layer ) ),
731 formatStringFromUTF32( m_pcb->GetLayerName( next_copper_layer ) ) );
732
733 layer_json["Notes"] = note;
734 }
735 else if( item->GetType() == BS_ITEM_TYPE_SOLDERMASK
736 || item->GetType() == BS_ITEM_TYPE_SILKSCREEN )
737 {
738 if( item->HasMaterialValue() )
739 {
740 layer_json["Material"] = item->GetMaterial();
741
742 // These constrains are only written if the board has impedance controlled tracks.
743 // If the board is not impedance controlled, they are useless.
744 // Do not add constrains that create more expensive boards.
745 if( brd_stackup.m_HasDielectricConstrains )
746 {
747 // Generate Epsilon R if > 1.0 (value <= 1.0 means not specified: it is not
748 // a possible value
749 if( item->GetEpsilonR() > 1.0 )
750 layer_json["DielectricConstant"] = item->FormatEpsilonR();
751
752 // Generate LossTangent > 0.0 (value <= 0.0 means not specified: it is not
753 // a possible value
754 if( item->GetLossTangent() > 0.0 )
755 layer_json["LossTangent"] = item->FormatLossTangent();
756 }
757 }
758
759 layer_json["Name"] = layer_name.c_str();
760 }
761 else
762 {
763 layer_json["Name"] = layer_name.c_str();
764 }
765
766 m_json["MaterialStackup"].insert( m_json["MaterialStackup"].end(), layer_json );
767 }
768 }
769}
const char * name
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
bool IsPrmSpecified(const wxString &aPrmValue)
@ BS_EDGE_CONNECTOR_BEVELLED
@ BS_ITEM_TYPE_COPPER
@ BS_ITEM_TYPE_SILKSCREEN
@ BS_ITEM_TYPE_DIELECTRIC
@ BS_ITEM_TYPE_SOLDERPASTE
@ BS_ITEM_TYPE_SOLDERMASK
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
wxString GetBuildVersion()
Get the full KiCad version string.
Manage one layer needed to make a physical board.
wxString GetTypeName() const
int GetSublayersCount() const
double GetEpsilonR(int aDielectricSubLayer=0) const
wxString GetColor(int aDielectricSubLayer=0) const
bool HasMaterialValue(int aDielectricSubLayer=0) const
PCB_LAYER_ID GetBrdLayerId() const
bool IsThicknessEditable() const
int GetThickness(int aDielectricSubLayer=0) const
BOARD_STACKUP_ITEM_TYPE GetType() const
wxString GetMaterial(int aDielectricSubLayer=0) const
wxString FormatEpsilonR(int aDielectricSubLayer=0) const
int GetDielectricLayerId() const
bool IsColorEditable() const
wxString FormatLossTangent(int aDielectricSubLayer=0) const
double GetLossTangent(int aDielectricSubLayer=0) const
Manage layers needed to make a physical board.
int GetCount() const
bool SynchronizeWithBoard(BOARD_DESIGN_SETTINGS *aSettings)
Synchronize the BOARD_STACKUP_ITEM* list with the board.
bool m_HasDielectricConstrains
True if some layers have impedance controlled tracks or have specific constrains for micro-wave appli...
BOARD_STACKUP_ITEM * GetStackupLayer(int aIndex)
bool m_EdgePlating
True if the edge board is plated.
BS_EDGE_CONNECTOR_CONSTRAINTS m_EdgeConnectorConstraints
If the board has edge connector cards, some constrains can be specified in job file: BS_EDGE_CONNECTO...
wxString m_FinishType
The name of external copper finish.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:372
constexpr size_type GetWidth() const
Definition box2.h:210
constexpr size_type GetHeight() const
Definition box2.h:211
void addJSONHeader()
Add the job file header in JSON format to m_JSONbuffer.
void addJSONMaterialStackup()
Add the Material Stackup section in JSON format to m_JSONbuffer This is the ordered list of stackup l...
void addJSONFilesAttributes()
Add the Files Attributes section in JSON format to m_JSONbuffer.
nlohmann::ordered_json m_json
bool CreateJobFile(const wxString &aFullFilename)
Creates a Gerber job file.
void addJSONGeneralSpecs()
Add the General Specs in JSON format to m_JSONbuffer.
bool WriteJSONJobFile(const wxString &aFullFilename)
Creates an Gerber job file in JSON format.
double mapValue(double aUiValue)
A helper function to convert a double in Pcbnew internal units to a JSON double value (in mm),...
const char * sideKeyValue(enum ONSIDE aValue)
void addJSONDesignRules()
Add the Design Rules section in JSON format to m_JSONbuffer.
std::string formatStringFromUTF32(const wxString &aText)
A helper function to convert a wxString ( therefore a Unicode text ) to a JSON compatible string (a e...
GERBER_JOBFILE_WRITER(BOARD *aPcb, REPORTER *aReporter=nullptr)
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
Definition pad.h:61
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:71
Handle a list of polygons defining a copper zone.
Definition zone.h:70
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, int aFlags)
Definition common.cpp:59
The common library.
#define _(s)
wxString GbrMakeProjectGUIDfromString(const wxString &aText)
Build a project GUID using format RFC4122 Version 1 or 4 from the project name, because a KiCad proje...
wxString GbrMakeCreationDateAttributeString(GBR_NC_STRING_FORMAT aFormat)
Handle special data (items attributes) during plot.
@ GBR_NC_STRING_FORMAT_GBRJOB
Classes used to generate a Gerber job file in JSON.
bool IsUserLayer(PCB_LAYER_ID aLayerId)
Test whether a layer is a non copper and a non tech layer.
Definition layer_ids.h:757
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:675
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ F_CrtYd
Definition layer_ids.h:112
@ B_Adhes
Definition layer_ids.h:99
@ Edge_Cuts
Definition layer_ids.h:108
@ F_Paste
Definition layer_ids.h:100
@ F_Adhes
Definition layer_ids.h:98
@ B_Mask
Definition layer_ids.h:94
@ B_Cu
Definition layer_ids.h:61
@ F_Mask
Definition layer_ids.h:93
@ B_Paste
Definition layer_ids.h:101
@ F_Fab
Definition layer_ids.h:115
@ Margin
Definition layer_ids.h:109
@ F_SilkS
Definition layer_ids.h:96
@ B_CrtYd
Definition layer_ids.h:111
@ In1_Cu
Definition layer_ids.h:62
@ B_SilkS
Definition layer_ids.h:97
@ F_Cu
Definition layer_ids.h:60
@ B_Fab
Definition layer_ids.h:114
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_ACTION
const std::vector< FAB_LAYER_COLOR > & GetStandardColors(BOARD_STACKUP_ITEM_TYPE aType)
nlohmann::json output
VECTOR2I end
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:90
Definition of file extensions used in Kicad.