KiCad PCB EDA Suite
Loading...
Searching...
No Matches
cadstar_pcb_archive_loader.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-2021 Roberto Fernandez Bautista <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * 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
27
29#include <board_stackup_manager/stackup_predefined_prms.h> // KEY_COPPER, KEY_CORE, KEY_PREPREG
30#include <board.h>
33#include <pcb_dimension.h>
34#include <pcb_shape.h>
35#include <footprint.h>
36#include <pad.h>
37#include <pcb_group.h>
38#include <pcb_text.h>
39#include <project.h>
40#include <pcb_track.h>
41#include <progress_reporter.h>
42#include <zone.h>
44#include <trigo.h>
45#include <macros.h>
46#include <wx/debug.h>
47#include <wx/log.h>
48
49#include <limits> // std::numeric_limits
50
51
53{
54 m_board = aBoard;
55 m_project = aProject;
56
58 m_progressReporter->SetNumPhases( 3 ); // (0) Read file, (1) Parse file, (2) Load file
59
60 Parse();
61
62 LONGPOINT designLimit = Assignments.Technology.DesignLimit;
63
64 //Note: can't use getKiCadPoint() due wxPoint being int - need long long to make the check
65 long long designSizeXkicad = (long long) designLimit.x * KiCadUnitMultiplier;
66 long long designSizeYkicad = (long long) designLimit.y * KiCadUnitMultiplier;
67
68 // Max size limited by the positive dimension of wxPoint (which is an int)
69 long long maxDesignSizekicad = std::numeric_limits<int>::max();
70
71 if( designSizeXkicad > maxDesignSizekicad || designSizeYkicad > maxDesignSizekicad )
72 {
73 // Note that we allow the floating point output here because this message is displayed to the user and should
74 // be in their locale.
75 THROW_IO_ERRORF( _( "The design is too large and cannot be imported into KiCad. \n"
76 "Please reduce the maximum design size in CADSTAR by navigating to: \n"
77 "Design Tab -> Properties -> Design Options -> Maximum Design Size. \n"
78 "Current Design size: %.2f, %.2f millimeters. \n" //format:allow
79 "Maximum permitted design size: %.2f, %.2f millimeters.\n" ), //format:allow
80 (double) designSizeXkicad / PCB_IU_PER_MM,
81 (double) designSizeYkicad / PCB_IU_PER_MM,
82 (double) maxDesignSizekicad / PCB_IU_PER_MM,
83 (double) maxDesignSizekicad / PCB_IU_PER_MM );
84 }
85
87 ( Assignments.Technology.DesignArea.first + Assignments.Technology.DesignArea.second )
88 / 2;
89
90 if( Layout.NetSynch == NETSYNCH::WARNING )
91 {
93 _( "The selected file indicates that nets might be out of synchronisation "
94 "with the schematic. It is recommended that you carry out an 'Align Nets' "
95 "procedure in CADSTAR and re-import, to avoid inconsistencies between the "
96 "PCB and the schematic. " ) );
97 }
98
100 {
101 m_progressReporter->BeginPhase( 2 );
102
103 // Significantly most amount of time spent loading coppers compared to all the other steps
104 // (39 seconds vs max of 100ms in other steps). This is due to requirement of boolean
105 // operations to join them together into a single polygon.
106 long numSteps = Layout.Coppers.size();
107
108 // A large amount is also spent calculating zone priorities
109 numSteps += ( Layout.Templates.size() * Layout.Templates.size() ) / 2;
110
111 m_progressReporter->SetMaxProgress( numSteps );
112 }
113
118 loadGroups();
119 loadBoards();
120 loadFigures();
121 loadTexts();
123 loadAreas();
127 loadCoppers(); // Progress reporting is here as significantly most amount of time spent
128
130 {
131 if( !calculateZonePriorities( id ) )
132 {
133 reportError( wxString::Format( _( "Unable to determine zone fill priorities for layer "
134 "'%s'. A best attempt has been made but it is "
135 "possible that DRC errors exist and that manual "
136 "editing of the zone priorities is required." ),
137 m_board->GetLayerName( id ) ) );
138 }
139 }
140
141 loadNets();
143
144 if( Layout.Trunks.size() > 0 )
145 {
147 _( "The CADSTAR design contains Trunk routing elements, which have no KiCad "
148 "equivalent. These elements were not loaded." ) );
149 }
150
151 if( Layout.VariantHierarchy.Variants.size() > 0 )
152 {
153 reportWarning( wxString::Format(
154 _( "The CADSTAR design contains variants which has no KiCad equivalent. Only "
155 "the variant '%s' was loaded." ),
156 Layout.VariantHierarchy.Variants.begin()->second.Name ) );
157 }
158
159 if( Layout.ReuseBlocks.size() > 0 )
160 {
162 _( "The CADSTAR design contains re-use blocks which has no KiCad equivalent. The "
163 "re-use block information has been discarded during the import." ) );
164 }
165
166 reportWarning( _( "CADSTAR fonts are different to the ones in KiCad. This will likely result "
167 "in alignment issues that may cause DRC errors. Please review the imported "
168 "text elements carefully and correct manually if required." ) );
169
171 _( "The CADSTAR design has been imported successfully.\n"
172 "Please review the import errors and warnings (if any)." ) );
173}
174
176{
177 std::vector<FOOTPRINT*> retval;
178
179 for( std::pair<SYMDEF_ID, FOOTPRINT*> fpPair : m_libraryMap )
180 {
181 retval.push_back( static_cast<FOOTPRINT*>( fpPair.second->Clone() ) );
182 }
183
184 return retval;
185}
186
187
188std::vector<std::unique_ptr<FOOTPRINT>> CADSTAR_PCB_ARCHIVE_LOADER::LoadLibrary()
189{
190 // loading the library after parsing takes almost no time in comparison
192 m_progressReporter->SetNumPhases( 2 ); // (0) Read file, (1) Parse file
193
194 Parse( true /*aLibrary*/);
195
196 // Some memory handling
197 for( std::pair<SYMDEF_ID, FOOTPRINT*> libItem : m_libraryMap )
198 {
199 FOOTPRINT* footprint = libItem.second;
200
201 if( footprint )
202 delete footprint;
203 }
204
205 m_libraryMap.clear();
206
207 if( m_board )
208 delete m_board;
209
210 m_board = new BOARD(); // dummy board for loading
211 m_project = nullptr;
212 m_designCenter = { 0, 0 }; // load footprints at 0,0
213
217
218 std::vector<std::unique_ptr<FOOTPRINT>> retval;
219
220 for( auto& [id, footprint] : m_libraryMap )
221 {
222 footprint->SetParent( nullptr ); // remove association to m_board
223 retval.emplace_back( footprint );
224 }
225
226 delete m_board;
227
228 // Don't delete the generated footprints, but empty the map
229 // (the destructor of this class would end up deleting them if not)
230 m_libraryMap.clear();
231
232 return retval;
233}
234
235
236void CADSTAR_PCB_ARCHIVE_LOADER::logBoardStackupWarning( const wxString& aCadstarLayerName,
237 const PCB_LAYER_ID& aKiCadLayer )
238{
240 {
241 reportWarning( wxString::Format(
242 _( "The CADSTAR layer '%s' has no KiCad equivalent. All elements on this "
243 "layer have been mapped to KiCad layer '%s' instead." ),
244 aCadstarLayerName, LSET::Name( aKiCadLayer ) ) );
245 }
246}
247
248
249void CADSTAR_PCB_ARCHIVE_LOADER::logBoardStackupMessage( const wxString& aCadstarLayerName,
250 const PCB_LAYER_ID& aKiCadLayer )
251{
253 {
254 reportInfo( wxString::Format(
255 _( "The CADSTAR layer '%s' has been assumed to be a technical layer. All "
256 "elements on this layer have been mapped to KiCad layer '%s'." ),
257 aCadstarLayerName, LSET::Name( aKiCadLayer ) ) );
258 }
259}
260
261
263 BOARD_STACKUP_ITEM* aKiCadItem,
264 int aDielectricSublayer )
265{
266 if( !aCadstarLayer.MaterialId.IsEmpty() )
267 {
268 MATERIAL material = Assignments.Layerdefs.Materials.at( aCadstarLayer.MaterialId );
269
270 aKiCadItem->SetMaterial( material.Name, aDielectricSublayer );
271 aKiCadItem->SetEpsilonR( material.Permittivity.GetDouble(), aDielectricSublayer );
272 aKiCadItem->SetLossTangent( material.LossTangent.GetDouble(), aDielectricSublayer );
273 //TODO add Resistivity when KiCad supports it
274 }
275
276 if( !aCadstarLayer.Name.IsEmpty() )
277 aKiCadItem->SetLayerName( aCadstarLayer.Name );
278
279 if( aCadstarLayer.Thickness != 0 )
280 aKiCadItem->SetThickness( getKiCadLength( aCadstarLayer.Thickness ), aDielectricSublayer );
281}
282
283
285{
286 // Structure describing an electrical layer with optional dielectric layers below it
287 // (construction layers in CADSTAR)
288 struct LAYER_BLOCK
289 {
290 LAYER_ID ElecLayerID = wxEmptyString; // Normally not empty, but could be empty if the
291 // first layer in the stackup is a construction
292 // layer
293 std::vector<LAYER_ID> ConstructionLayers; // Normally empty for the last electrical layer
294 // but it is possible to build a board in CADSTAR
295 // with no construction layers or with the bottom
296 // layer being a construction layer
297
298 bool IsInitialised() { return !ElecLayerID.IsEmpty() || ConstructionLayers.size() > 0; };
299 };
300
301 std::vector<LAYER_BLOCK> cadstarBoardStackup;
302 LAYER_BLOCK currentBlock;
303 bool first = true;
304
305 // Find the electrical and construction (dielectric) layers in the stackup
306 for( LAYER_ID cadstarLayerID : Assignments.Layerdefs.LayerStack )
307 {
308 LAYER cadstarLayer = Assignments.Layerdefs.Layers.at( cadstarLayerID );
309
310 if( cadstarLayer.Type == LAYER_TYPE::JUMPERLAYER ||
311 cadstarLayer.Type == LAYER_TYPE::POWER ||
312 cadstarLayer.Type == LAYER_TYPE::ELEC )
313 {
314 if( currentBlock.IsInitialised() )
315 {
316 cadstarBoardStackup.push_back( currentBlock );
317 currentBlock = LAYER_BLOCK(); // reset the block
318 }
319
320 currentBlock.ElecLayerID = cadstarLayerID;
321 first = false;
322 }
323 else if( cadstarLayer.Type == LAYER_TYPE::CONSTRUCTION )
324 {
325 if( first )
326 {
327 reportWarning( wxString::Format( _( "The CADSTAR construction layer '%s' is on "
328 "the outer surface of the board. It has been "
329 "ignored." ),
330 cadstarLayer.Name ) );
331 }
332 else
333 {
334 currentBlock.ConstructionLayers.push_back( cadstarLayerID );
335 }
336 }
337 }
338
339 if( currentBlock.IsInitialised() )
340 cadstarBoardStackup.push_back( currentBlock );
341
342 m_numCopperLayers = cadstarBoardStackup.size();
343
344 // Special case: last layer in the stackup is a construction layer, drop it
345 if( cadstarBoardStackup.back().ConstructionLayers.size() > 0 )
346 {
347 for( const LAYER_ID& layerID : cadstarBoardStackup.back().ConstructionLayers )
348 {
349 LAYER cadstarLayer = Assignments.Layerdefs.Layers.at( layerID );
350
351 reportWarning( wxString::Format( _( "The CADSTAR construction layer '%s' is on "
352 "the outer surface of the board. It has been "
353 "ignored." ),
354 cadstarLayer.Name ) );
355 }
356
357 cadstarBoardStackup.back().ConstructionLayers.clear();
358 }
359
360 // Make sure it is an even number of layers (KiCad doesn't yet support unbalanced stack-ups)
361 if( ( m_numCopperLayers % 2 ) != 0 )
362 {
363 LAYER_BLOCK bottomLayer = cadstarBoardStackup.back();
364 cadstarBoardStackup.pop_back();
365
366 LAYER_BLOCK secondToLastLayer = cadstarBoardStackup.back();
367 cadstarBoardStackup.pop_back();
368
369 LAYER_BLOCK dummyLayer;
370
371 if( secondToLastLayer.ConstructionLayers.size() > 0 )
372 {
373 LAYER_ID lastConstruction = secondToLastLayer.ConstructionLayers.back();
374
375 if( secondToLastLayer.ConstructionLayers.size() > 1 )
376 {
377 // At least two construction layers, lets remove one here and use the
378 // other in the dummy layer
379 secondToLastLayer.ConstructionLayers.pop_back();
380 }
381 else
382 {
383 // There is only one construction layer, lets halve its thickness so it is split
384 // evenly between this layer and the dummy layer
385 Assignments.Layerdefs.Layers.at( lastConstruction ).Thickness /= 2;
386 }
387
388 dummyLayer.ConstructionLayers.push_back( lastConstruction );
389 }
390
391 cadstarBoardStackup.push_back( secondToLastLayer );
392 cadstarBoardStackup.push_back( dummyLayer );
393 cadstarBoardStackup.push_back( bottomLayer );
395 }
396
397 wxASSERT( m_numCopperLayers == (int) cadstarBoardStackup.size() );
398 wxASSERT( cadstarBoardStackup.back().ConstructionLayers.size() == 0 );
399
400 // Create a new stackup from default stackup list
401 BOARD_DESIGN_SETTINGS& boardDesignSettings = m_board->GetDesignSettings();
402 BOARD_STACKUP& stackup = boardDesignSettings.GetStackupDescriptor();
403 stackup.RemoveAll();
404 m_board->SetEnabledLayers( LSET::AllLayersMask() );
405 m_board->SetVisibleLayers( LSET::AllLayersMask() );
406 m_board->SetCopperLayerCount( m_numCopperLayers );
407 stackup.BuildDefaultStackupList( &m_board->GetDesignSettings(), m_numCopperLayers );
408
409 size_t stackIndex = 0;
410
411 for( BOARD_STACKUP_ITEM* item : stackup.GetList() )
412 {
413 if( item->GetType() == BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_COPPER )
414 {
415 LAYER_ID layerID = cadstarBoardStackup.at( stackIndex ).ElecLayerID;
416
417 if( layerID.IsEmpty() )
418 {
419 // Loading a dummy layer. Make zero thickness so it doesn't affect overall stackup
420 item->SetThickness( 0 );
421 }
422 else
423 {
424 LAYER copperLayer = Assignments.Layerdefs.Layers.at( layerID );
425 initStackupItem( copperLayer, item, 0 );
426 LAYER_T copperType = LAYER_T::LT_SIGNAL;
427
428 switch( copperLayer.Type )
429 {
431 copperType = LAYER_T::LT_JUMPER;
432 break;
433
434 case LAYER_TYPE::ELEC:
435 copperType = LAYER_T::LT_SIGNAL;
436 break;
437
439 copperType = LAYER_T::LT_POWER;
440 m_powerPlaneLayers.push_back( copperLayer.ID ); //need to add a Copper zone
441 break;
442
443 default:
444 wxFAIL_MSG( wxT( "Unexpected Layer type. Was expecting an electrical type" ) );
445 break;
446 }
447
448 m_board->SetLayerType( item->GetBrdLayerId(), copperType );
449 m_board->SetLayerName( item->GetBrdLayerId(), item->GetLayerName() );
450 m_layermap.insert( { copperLayer.ID, item->GetBrdLayerId() } );
451 }
452 }
453 else if( item->GetType() == BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_DIELECTRIC )
454 {
455 LAYER_BLOCK layerBlock = cadstarBoardStackup.at( stackIndex );
456 LAYER_BLOCK layerBlockBelow = cadstarBoardStackup.at( stackIndex + 1 );
457
458 if( layerBlock.ConstructionLayers.size() == 0 )
459 {
460 ++stackIndex;
461 continue; // Older cadstar designs have no construction layers - use KiCad defaults
462 }
463
464 int dielectricId = stackIndex + 1;
465 item->SetDielectricLayerId( dielectricId );
466
467 //Prepreg or core?
468 //Look at CADSTAR layer embedding (see LAYER->Embedding) to check whether the electrical
469 //layer embeds above and below to decide if current layer is prepreg or core
470 if( layerBlock.ElecLayerID.IsEmpty() )
471 {
472 //Dummy electrical layer, assume prepreg
473 item->SetTypeName( KEY_PREPREG );
474 }
475 else
476 {
477 LAYER copperLayer = Assignments.Layerdefs.Layers.at( layerBlock.ElecLayerID );
478
479 if( layerBlockBelow.ElecLayerID.IsEmpty() )
480 {
481 // Dummy layer below, just use current layer to decide
482
483 if( copperLayer.Embedding == EMBEDDING::ABOVE )
484 item->SetTypeName( KEY_CORE );
485 else
486 item->SetTypeName( KEY_PREPREG );
487 }
488 else
489 {
490 LAYER copperLayerBelow =
491 Assignments.Layerdefs.Layers.at( layerBlockBelow.ElecLayerID );
492
493 if( copperLayer.Embedding == EMBEDDING::ABOVE )
494 {
495 // Need to check layer below is embedding downwards
496 if( copperLayerBelow.Embedding == EMBEDDING::BELOW )
497 item->SetTypeName( KEY_CORE );
498 else
499 item->SetTypeName( KEY_PREPREG );
500 }
501 else
502 {
503 item->SetTypeName( KEY_PREPREG );
504 }
505 }
506 }
507
508 int dielectricSublayer = 0;
509
510 for( LAYER_ID constructionLaID : layerBlock.ConstructionLayers )
511 {
512 LAYER dielectricLayer = Assignments.Layerdefs.Layers.at( constructionLaID );
513
514 if( dielectricSublayer )
515 item->AddDielectricPrms( dielectricSublayer );
516
517 initStackupItem( dielectricLayer, item, dielectricSublayer );
518 m_board->SetLayerName( item->GetBrdLayerId(), item->GetLayerName() );
519 m_layermap.insert( { dielectricLayer.ID, item->GetBrdLayerId() } );
520 ++dielectricSublayer;
521 }
522
523 ++stackIndex;
524 }
525 else if( item->GetType() == BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_SILKSCREEN )
526 {
527 item->SetColor( wxT( "White" ) );
528 }
529 else if( item->GetType() == BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_SOLDERMASK )
530 {
531 item->SetColor( wxT( "Green" ) );
532 }
533 }
534
535 int thickness = stackup.BuildBoardThicknessFromStackup();
536 boardDesignSettings.SetBoardThickness( thickness );
537 boardDesignSettings.m_HasStackup = true;
538
539 int numElecLayersProcessed = 0;
540
541 // Map CADSTAR documentation layers to KiCad "User layers"
542 int currentDocLayer = 0;
543 std::vector<PCB_LAYER_ID> docLayers = { Dwgs_User, Cmts_User, User_1, User_2, User_3, User_4,
545
546 for( LAYER_ID cadstarLayerID : Assignments.Layerdefs.LayerStack )
547 {
548 LAYER curLayer = Assignments.Layerdefs.Layers.at( cadstarLayerID );
550 wxString layerName = curLayer.Name.Lower();
551
552 enum class LOG_LEVEL
553 {
554 NONE,
555 MSG,
556 WARN
557 };
558
559 auto selectLayerID =
560 [&]( PCB_LAYER_ID aFront, PCB_LAYER_ID aBack, LOG_LEVEL aLogType )
561 {
562 if( numElecLayersProcessed >= m_numCopperLayers )
563 kicadLayerID = aBack;
564 else
565 kicadLayerID = aFront;
566
567 switch( aLogType )
568 {
569 case LOG_LEVEL::NONE:
570 break;
571
572 case LOG_LEVEL::MSG:
573 logBoardStackupMessage( curLayer.Name, kicadLayerID );
574 break;
575
576 case LOG_LEVEL::WARN:
577 logBoardStackupWarning( curLayer.Name, kicadLayerID );
578 break;
579 }
580 };
581
582 switch( curLayer.Type )
583 {
589 //Shouldn't be here if CPA file is correctly parsed and not corrupt
590 THROW_IO_ERRORF( _( "Unexpected layer '%s' in layer stack." ), curLayer.Name );
591 break;
592
594 case LAYER_TYPE::ELEC:
596 ++numElecLayersProcessed;
599 //Already dealt with these when loading board stackup
600 break;
601
602 case LAYER_TYPE::DOC:
603
604 if( currentDocLayer >= (int) docLayers.size() )
605 currentDocLayer = 0;
606
607 kicadLayerID = docLayers.at( currentDocLayer++ );
608 logBoardStackupMessage( curLayer.Name, kicadLayerID );
609 break;
610
612 switch( curLayer.SubType )
613 {
615 selectLayerID( PCB_LAYER_ID::F_Fab, PCB_LAYER_ID::B_Fab, LOG_LEVEL::NONE );
616 break;
617
619 selectLayerID( PCB_LAYER_ID::F_CrtYd, PCB_LAYER_ID::B_CrtYd, LOG_LEVEL::NONE );
620 break;
621
623 // Generic Non-electrical layer (older CADSTAR versions).
624 // Attempt to detect technical layers by string matching.
625 if( layerName.Contains( wxT( "glue" ) ) || layerName.Contains( wxT( "adhesive" ) ) )
626 {
627 selectLayerID( PCB_LAYER_ID::F_Adhes, PCB_LAYER_ID::B_Adhes, LOG_LEVEL::MSG );
628 }
629 else if( layerName.Contains( wxT( "silk" ) ) || layerName.Contains( wxT( "legend" ) ) )
630 {
631 selectLayerID( PCB_LAYER_ID::F_SilkS, PCB_LAYER_ID::B_SilkS, LOG_LEVEL::MSG );
632 }
633 else if( layerName.Contains( wxT( "assembly" ) ) || layerName.Contains( wxT( "fabrication" ) ) )
634 {
635 selectLayerID( PCB_LAYER_ID::F_Fab, PCB_LAYER_ID::B_Fab, LOG_LEVEL::MSG );
636 }
637 else if( layerName.Contains( wxT( "resist" ) ) || layerName.Contains( wxT( "mask" ) ) )
638 {
639 selectLayerID( PCB_LAYER_ID::F_Mask, PCB_LAYER_ID::B_Mask, LOG_LEVEL::MSG );
640 }
641 else if( layerName.Contains( wxT( "paste" ) ) )
642 {
643 selectLayerID( PCB_LAYER_ID::F_Paste, PCB_LAYER_ID::B_Paste, LOG_LEVEL::MSG );
644 }
645 else
646 {
647 // Does not appear to be a technical layer - Map to Eco layers for now.
649 LOG_LEVEL::WARN );
650 }
651 break;
652
654 selectLayerID( PCB_LAYER_ID::F_Paste, PCB_LAYER_ID::B_Paste, LOG_LEVEL::MSG );
655 break;
656
658 selectLayerID( PCB_LAYER_ID::F_SilkS, PCB_LAYER_ID::B_SilkS, LOG_LEVEL::MSG );
659 break;
660
662 selectLayerID( PCB_LAYER_ID::F_Mask, PCB_LAYER_ID::B_Mask, LOG_LEVEL::MSG );
663 break;
664
667 //Unsure what these layer types are used for. Map to Eco layers for now.
668 selectLayerID( PCB_LAYER_ID::Eco1_User, PCB_LAYER_ID::Eco2_User, LOG_LEVEL::WARN );
669 break;
670
671 default:
672 wxFAIL_MSG( wxT( "Unknown CADSTAR Layer Sub-type" ) );
673 break;
674 }
675 break;
676
677 default:
678 wxFAIL_MSG( wxT( "Unknown CADSTAR Layer Type" ) );
679 break;
680 }
681
682 m_layermap.insert( { curLayer.ID, kicadLayerID } );
683 }
684}
685
686
688{
689 LSET enabledLayers = m_board->GetEnabledLayers();
690 LSET validRemappingLayers = enabledLayers | LSET::AllBoardTechMask() |
692
693 std::vector<INPUT_LAYER_DESC> inputLayers;
694 std::map<wxString, LAYER_ID> cadstarLayerNameMap;
695
696 for( std::pair<LAYER_ID, PCB_LAYER_ID> layerPair : m_layermap )
697 {
698 LAYER* curLayer = &Assignments.Layerdefs.Layers.at( layerPair.first );
699
700 //Only remap documentation and non-electrical layers
701 if( curLayer->Type == LAYER_TYPE::NONELEC || curLayer->Type == LAYER_TYPE::DOC )
702 {
703 INPUT_LAYER_DESC iLdesc;
704 iLdesc.Name = curLayer->Name;
705 iLdesc.PermittedLayers = validRemappingLayers;
706 iLdesc.AutoMapLayer = layerPair.second;
707
708 inputLayers.push_back( iLdesc );
709 cadstarLayerNameMap.insert( { curLayer->Name, curLayer->ID } );
710 }
711 }
712
713 if( inputLayers.size() == 0 )
714 return;
715
716 // Callback:
717 std::map<wxString, PCB_LAYER_ID> reMappedLayers = m_layerMappingHandler( inputLayers );
718
719 for( std::pair<wxString, PCB_LAYER_ID> layerPair : reMappedLayers )
720 {
721 if( layerPair.second == PCB_LAYER_ID::UNDEFINED_LAYER )
722 {
723 wxFAIL_MSG( wxT( "Unexpected Layer ID" ) );
724 continue;
725 }
726
727 LAYER_ID cadstarLayerID = cadstarLayerNameMap.at( layerPair.first );
728 m_layermap.at( cadstarLayerID ) = layerPair.second;
729 enabledLayers |= LSET( { layerPair.second } );
730 }
731
732 m_board->SetEnabledLayers( enabledLayers );
733 m_board->SetVisibleLayers( enabledLayers );
734}
735
736
738{
739 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
740 std::map<SPACINGCODE_ID, SPACINGCODE>& spacingCodes = Assignments.Codedefs.SpacingCodes;
741
742 auto applyRule =
743 [&]( wxString aID, int* aVal )
744 {
745 if( spacingCodes.find( aID ) == spacingCodes.end() )
746 {
747 reportWarning( wxString::Format(
748 _( "Design rule %s was not found. This was ignored." ), aID ) );
749 }
750 else
751 *aVal = getKiCadLength( spacingCodes.at( aID ).Spacing );
752 };
753
754 //Note: for details on the different spacing codes see SPACINGCODE::ID
755
756 applyRule( "T_T", &bds.m_MinClearance );
757 applyRule( "C_B", &bds.m_CopperEdgeClearance );
758 applyRule( "H_H", &bds.m_HoleToHoleMin );
759
760 bds.m_TrackMinWidth = getKiCadLength( Assignments.Technology.MinRouteWidth );
761 bds.m_ViasMinSize = bds.m_TrackMinWidth; // Not specified, assumed same as track width
762 bds.m_ViasMinAnnularWidth = bds.m_TrackMinWidth / 2; // Not specified, assumed half track width
763 bds.m_MinThroughDrill = PCB_IU_PER_MM * 0.0508; // CADSTAR does not specify a minimum hole size
764 // so set to minimum permitted in KiCad (2 mils)
765 bds.m_HoleClearance = 0; // Testing suggests cadstar might not have a copper-to-hole clearance
766
767 auto applyNetClassRule = [&]( wxString aID, const std::shared_ptr<NETCLASS>& aNetClassPtr )
768 {
769 int value = -1;
770 applyRule( aID, &value );
771
772 if( value != -1 )
773 aNetClassPtr->SetClearance( value );
774 };
775
776 applyNetClassRule( "T_T", bds.m_NetSettings->GetDefaultNetclass() );
777
778 reportWarning( _( "KiCad design rules are different from CADSTAR ones. Only the compatible "
779 "design rules were imported. It is recommended that you review the design "
780 "rules that have been applied." ) );
781}
782
783
785{
786 for( std::pair<SYMDEF_ID, SYMDEF_PCB> symPair : Library.ComponentDefinitions )
787 {
788 SYMDEF_ID key = symPair.first;
789 SYMDEF_PCB component = symPair.second;
790
791 // Check that we are not loading a documentation symbol.
792 // Documentation symbols in CADSTAR are graphical "footprints" that can be assigned
793 // to any layer. The definition in the library assigns all elements to an undefined layer.
794 LAYER_ID componentLayer;
795
796 if( component.Figures.size() > 0 )
797 {
798 FIGURE firstFigure = component.Figures.begin()->second;
799 componentLayer = firstFigure.LayerID;
800 }
801 else if( component.Texts.size() > 0 )
802 {
803 TEXT firstText = component.Texts.begin()->second;
804 componentLayer = firstText.LayerID;
805 }
806
807 if( !componentLayer.IsEmpty() && getLayerType( componentLayer ) == LAYER_TYPE::NOLAYER )
808 continue; // don't process documentation symbols
809
810 FOOTPRINT* footprint = new FOOTPRINT( m_board );
811 footprint->SetPosition( getKiCadPoint( component.Origin ) );
812
813 LIB_ID libID;
814 libID.Parse( component.BuildLibName(), true );
815
816 footprint->SetFPID( libID );
817 loadLibraryFigures( component, footprint );
818 loadLibraryAreas( component, footprint );
819 loadLibraryPads( component, footprint );
820 loadLibraryCoppers( component, footprint ); // Load coppers after pads to ensure correct
821 // ordering of pads in footprint->Pads()
822
823 footprint->SetPosition( { 0, 0 } ); // KiCad expects library footprints at 0,0
824 footprint->SetReference( wxT( "REF**" ) );
825 footprint->SetValue( libID.GetLibItemName() );
826 footprint->AutoPositionFields();
827 m_libraryMap.insert( std::make_pair( key, footprint ) );
828 }
829}
830
831
833 FOOTPRINT* aFootprint )
834{
835 for( std::pair<FIGURE_ID, FIGURE> figPair : aComponent.Figures )
836 {
837 FIGURE& fig = figPair.second;
838
839 for( const PCB_LAYER_ID& layer : getKiCadLayerSet( fig.LayerID ).Seq() )
840 {
842 layer,
844 wxString::Format( wxT( "Component %s:%s -> Figure %s" ),
845 aComponent.ReferenceName,
846 aComponent.Alternate,
847 fig.ID ),
848 aFootprint );
849 }
850 }
851}
852
853
855 FOOTPRINT* aFootprint )
856{
857 for( COMPONENT_COPPER compCopper : aComponent.ComponentCoppers )
858 {
859 int lineThickness = getKiCadLength( getCopperCode( compCopper.CopperCodeID ).CopperWidth );
860 LSET layers = getKiCadLayerSet( compCopper.LayerID );
861 LSET copperLayers = LSET::AllCuMask() & layers;
862 LSET remainingLayers = layers;
863
864 if( compCopper.AssociatedPadIDs.size() > 0 && copperLayers.count() > 0
865 && compCopper.Shape.Type == SHAPE_TYPE::SOLID )
866 {
867 // The copper is associated with pads and in an electrical layer which means it can
868 // have a net associated with it. Load as a pad instead.
869 // Note: we can only handle SOLID copper shapes. If the copper shape is an outline or
870 // hatched or outline, then we give up and load as a graphical shape instead.
871
872 // Find the first non-PCB-only pad. If there are none, use the first one
873 COMPONENT_PAD anchorPad;
874 bool found = false;
875
876 for( PAD_ID padID : compCopper.AssociatedPadIDs )
877 {
878 anchorPad = aComponent.ComponentPads.at( padID );
879
880 if( !anchorPad.PCBonlyPad )
881 {
882 found = true;
883 break;
884 }
885 }
886
887 if( !found )
888 anchorPad = aComponent.ComponentPads.at( compCopper.AssociatedPadIDs.front() );
889
890 std::unique_ptr<PAD> pad = std::make_unique<PAD>( aFootprint );
891 pad->SetAttribute( PAD_ATTRIB::SMD );
892 pad->SetLayerSet( copperLayers );
893 pad->SetNumber( anchorPad.Identifier.IsEmpty() ? wxString::Format( wxT( "%ld" ), anchorPad.ID )
894 : anchorPad.Identifier );
895
896 // Custom pad shape with an anchor at the position of one of the associated
897 // pads and same size as the pad. Shape circle as it fits inside a rectangle
898 // but not the other way round
899 PADCODE anchorpadcode = getPadCode( anchorPad.PadCodeID );
900 int anchorSize = getKiCadLength( anchorpadcode.Shape.Size );
901 VECTOR2I anchorPos = getKiCadPoint( anchorPad.Position );
902
903 if( anchorSize <= 0 )
904 anchorSize = 1;
905
907 pad->SetAnchorPadShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::CIRCLE );
908 pad->SetSize( PADSTACK::ALL_LAYERS, { anchorSize, anchorSize } );
909 pad->SetPosition( anchorPos );
910
911 SHAPE_POLY_SET shapePolys = getPolySetFromCadstarShape( compCopper.Shape, lineThickness, aFootprint );
912 shapePolys.Move( -anchorPos );
913 pad->AddPrimitivePoly( PADSTACK::ALL_LAYERS, shapePolys, 0, true );
914
915 // Now renumber all the associated pads
916 COMPONENT_PAD associatedPad;
917
918 for( PAD_ID padID : compCopper.AssociatedPadIDs )
919 {
920 PAD* assocPad = getPadReference( aFootprint, padID );
921 assocPad->SetNumber( pad->GetNumber() );
922 }
923
924 aFootprint->Add( pad.release(), ADD_MODE::APPEND ); // Append so that we get the correct behaviour
925 // when finding pads by PAD_ID. See loadNets()
926
927 m_librarycopperpads[aComponent.ID][anchorPad.ID].push_back( aFootprint->Pads().size() );
928
929 remainingLayers ^= copperLayers; // don't process copper layers again!
930 }
931
932 if( remainingLayers.any() )
933 {
934 for( const PCB_LAYER_ID& layer : remainingLayers.Seq() )
935 {
936 drawCadstarShape( compCopper.Shape, layer, lineThickness,
937 wxString::Format( wxT( "Component %s:%s -> Copper element" ),
938 aComponent.ReferenceName, aComponent.Alternate ),
939 aFootprint );
940 }
941 }
942 }
943}
944
945
947 FOOTPRINT* aFootprint )
948{
949 for( std::pair<COMP_AREA_ID, COMPONENT_AREA> areaPair : aComponent.ComponentAreas )
950 {
951 COMPONENT_AREA& area = areaPair.second;
952
953 if( area.NoVias || area.NoTracks )
954 {
955 int lineThickness = 0; // CADSTAR areas only use the line width for display purpose
956 ZONE* zone = getZoneFromCadstarShape( area.Shape, lineThickness, aFootprint );
957
958 aFootprint->Add( zone, ADD_MODE::APPEND );
959
960 if( isLayerSet( area.LayerID ) )
961 zone->SetLayerSet( getKiCadLayerSet( area.LayerID ) );
962 else
963 zone->SetLayer( getKiCadLayer( area.LayerID ) );
964
965 zone->SetIsRuleArea( true ); //import all CADSTAR areas as Keepout zones
966 zone->SetDoNotAllowPads( false ); //no CADSTAR equivalent
967 zone->SetZoneName( area.ID );
968
969 //There is no distinction between tracks and copper pours in CADSTAR Keepout zones
970 zone->SetDoNotAllowTracks( area.NoTracks );
971 zone->SetDoNotAllowZoneFills( area.NoTracks );
972
973 zone->SetDoNotAllowVias( area.NoVias );
974 }
975 else
976 {
977 wxString libName = aComponent.ReferenceName;
978
979 if( !aComponent.Alternate.IsEmpty() )
980 libName << wxT( " (" ) << aComponent.Alternate << wxT( ")" );
981
982 reportError( wxString::Format( _( "The CADSTAR area '%s' in library component '%s' does not "
983 "have a KiCad equivalent. The area is neither a via nor "
984 "route keepout area. The area was not imported." ),
985 area.ID, libName ) );
986 }
987 }
988}
989
990
992 FOOTPRINT* aFootprint )
993{
994 for( std::pair<PAD_ID, COMPONENT_PAD> padPair : aComponent.ComponentPads )
995 {
996 if( PAD* pad = getKiCadPad( padPair.second, aFootprint ) )
997 {
998 aFootprint->Add( pad, ADD_MODE::APPEND ); // Append so that we get correct behaviour
999 // when finding pads by PAD_ID - see loadNets()
1000 }
1001 }
1002}
1003
1004
1006{
1007 PADCODE csPadcode = getPadCode( aCadstarPad.PadCodeID );
1008 wxString errorMSG;
1009
1010 std::unique_ptr<PAD> pad = std::make_unique<PAD>( aParent );
1011 LSET padLayerSet;
1012
1013 switch( aCadstarPad.Side )
1014 {
1015 case PAD_SIDE::MAXIMUM: //Bottom side
1016 padLayerSet |= LSET( { B_Cu, B_Paste, B_Mask } );
1017 break;
1018
1019 case PAD_SIDE::MINIMUM: //TOP side
1020 padLayerSet |= LSET( { F_Cu, F_Paste, F_Mask } );
1021 break;
1022
1024 padLayerSet = LSET::AllCuMask( m_numCopperLayers ) | LSET( { F_Mask, B_Mask, F_Paste, B_Paste } );
1025 break;
1026
1027 default:
1028 wxFAIL_MSG( wxT( "Unknown Pad type" ) );
1029 }
1030
1031 pad->SetAttribute( PAD_ATTRIB::SMD ); // assume SMD pad for now
1032 pad->SetLocalSolderMaskMargin( 0 );
1033 pad->SetLocalSolderPasteMargin( 0 );
1034 pad->SetLocalSolderPasteMarginRatio( 0.0 );
1035 bool complexPadErrorLogged = false;
1036
1037 for( auto& [layer, shape] : csPadcode.Reassigns )
1038 {
1039 PCB_LAYER_ID kiLayer = getKiCadLayer( layer );
1040
1041 if( shape.Size == 0 )
1042 {
1043 if( kiLayer > UNDEFINED_LAYER )
1044 padLayerSet.reset( kiLayer );
1045 }
1046 else
1047 {
1048 int newMargin = getKiCadLength( shape.Size - csPadcode.Shape.Size ) / 2;
1049
1050 if( kiLayer == F_Mask || kiLayer == B_Mask )
1051 {
1052 std::optional<int> localMargin = pad->GetLocalSolderMaskMargin();
1053
1054 if( !localMargin.has_value() )
1055 pad->SetLocalSolderMaskMargin( newMargin );
1056 else if( std::abs( localMargin.value() ) < std::abs( newMargin ) )
1057 pad->SetLocalSolderMaskMargin( newMargin );
1058 }
1059 else if( kiLayer == F_Paste || kiLayer == B_Paste )
1060 {
1061 std::optional<int> localMargin = pad->GetLocalSolderPasteMargin();
1062
1063 if( !localMargin.has_value() )
1064 pad->SetLocalSolderPasteMargin( newMargin );
1065 else if( std::abs( localMargin.value() ) < std::abs( newMargin ) )
1066 pad->SetLocalSolderPasteMargin( newMargin );
1067 }
1068 else
1069 {
1070 //TODO fix properly
1071
1072 if( !complexPadErrorLogged )
1073 {
1074 complexPadErrorLogged = true;
1075 errorMSG += wxT( "\n - " )
1076 + wxString::Format( _( "The CADSTAR pad definition '%s' is a complex pad stack, "
1077 "which is not supported in KiCad. Please review the "
1078 "imported pads as they may require manual correction." ),
1079 csPadcode.Name );
1080 }
1081 }
1082 }
1083 }
1084
1085 pad->SetLayerSet( padLayerSet );
1086
1087 if( aCadstarPad.PCBonlyPad )
1088 {
1089 // PCB Only pads in CADSTAR do not have a representation in the schematic - they are
1090 // purely mechanical pads that have no net associated with them. Make the pad name
1091 // empty to avoid warnings when importing from the schematic
1092 pad->SetNumber( wxT( "" ) );
1093 }
1094 else
1095 {
1096 pad->SetNumber( aCadstarPad.Identifier.IsEmpty() ? wxString::Format( wxT( "%ld" ), aCadstarPad.ID )
1097 : aCadstarPad.Identifier );
1098 }
1099
1100 if( csPadcode.Shape.Size == 0 )
1101 {
1102 if( csPadcode.DrillDiameter == UNDEFINED_VALUE && aCadstarPad.Side == PAD_SIDE::THROUGH_HOLE )
1103 {
1104 // Through-hole, zero sized pad? Lets load this just on the F_Mask for now to
1105 // prevent DRC errors.
1106 // TODO: This could be a custom padstack
1107 pad->SetAttribute( PAD_ATTRIB::SMD );
1108 pad->SetLayerSet( LSET( { F_Mask } ) );
1109 }
1110
1111 // zero sized pads seems to break KiCad so lets make it very small instead
1112 csPadcode.Shape.Size = 1;
1113 }
1114
1115 VECTOR2I padOffset = { 0, 0 }; // offset of the pad origin (before rotating)
1116 VECTOR2I drillOffset = { 0, 0 }; // offset of the drill origin w.r.t. the pad (before rotating)
1117
1118 switch( csPadcode.Shape.ShapeType )
1119 {
1121 //todo fix: use custom shape instead (Donught shape, i.e. a circle with a hole)
1123 pad->SetSize( PADSTACK::ALL_LAYERS, { getKiCadLength( csPadcode.Shape.Size ),
1124 getKiCadLength( csPadcode.Shape.Size ) } );
1125 break;
1126
1129 pad->SetSize( PADSTACK::ALL_LAYERS,
1130 { getKiCadLength( (long long) csPadcode.Shape.Size
1131 + (long long) csPadcode.Shape.LeftLength
1132 + (long long) csPadcode.Shape.RightLength ),
1133 getKiCadLength( csPadcode.Shape.Size ) } );
1134 pad->SetChamferPositions( PADSTACK::ALL_LAYERS,
1137 pad->SetRoundRectRadiusRatio( PADSTACK::ALL_LAYERS, 0.5 );
1138 pad->SetChamferRectRatio( PADSTACK::ALL_LAYERS, 0.0 );
1139
1140 padOffset.x = getKiCadLength( ( (long long) csPadcode.Shape.LeftLength / 2 ) -
1141 ( (long long) csPadcode.Shape.RightLength / 2 ) );
1142 break;
1143
1146 pad->SetSize( PADSTACK::ALL_LAYERS, { getKiCadLength( csPadcode.Shape.Size ),
1147 getKiCadLength( csPadcode.Shape.Size ) } );
1148 break;
1149
1151 {
1152 // Cadstar diamond shape is a square rotated 45 degrees
1153 // We convert it in KiCad to a square with chamfered edges
1154 int sizeOfSquare = (double) getKiCadLength( csPadcode.Shape.Size ) * sqrt(2.0);
1156 pad->SetChamferRectRatio( PADSTACK::ALL_LAYERS, 0.5 );
1157 pad->SetSize( PADSTACK::ALL_LAYERS, { sizeOfSquare, sizeOfSquare } );
1158
1159 padOffset.x = getKiCadLength( ( (long long) csPadcode.Shape.LeftLength / 2 ) -
1160 ( (long long) csPadcode.Shape.RightLength / 2 ) );
1161 }
1162 break;
1163
1166 pad->SetSize( PADSTACK::ALL_LAYERS,
1167 { getKiCadLength( (long long) csPadcode.Shape.Size
1168 + (long long) csPadcode.Shape.LeftLength
1169 + (long long) csPadcode.Shape.RightLength ),
1170 getKiCadLength( csPadcode.Shape.Size ) } );
1171
1172 padOffset.x = getKiCadLength( ( (long long) csPadcode.Shape.LeftLength / 2 ) -
1173 ( (long long) csPadcode.Shape.RightLength / 2 ) );
1174 break;
1175
1179 pad->SetChamferRectRatio( PADSTACK::ALL_LAYERS, 0.25 );
1180 pad->SetSize( PADSTACK::ALL_LAYERS, { getKiCadLength( csPadcode.Shape.Size ),
1181 getKiCadLength( csPadcode.Shape.Size ) } );
1182 break;
1183
1186 pad->SetSize( PADSTACK::ALL_LAYERS,
1187 { getKiCadLength( (long long) csPadcode.Shape.Size
1188 + (long long) csPadcode.Shape.LeftLength
1189 + (long long) csPadcode.Shape.RightLength ),
1190 getKiCadLength( csPadcode.Shape.Size ) } );
1191
1192 padOffset.x = getKiCadLength( ( (long long) csPadcode.Shape.LeftLength / 2 ) -
1193 ( (long long) csPadcode.Shape.RightLength / 2 ) );
1194 break;
1195
1198 pad->SetRoundRectCornerRadius( PADSTACK::ALL_LAYERS,
1199 getKiCadLength( csPadcode.Shape.InternalFeature ) );
1200 pad->SetSize( PADSTACK::ALL_LAYERS,
1201 { getKiCadLength( (long long) csPadcode.Shape.Size
1202 + (long long) csPadcode.Shape.LeftLength
1203 + (long long) csPadcode.Shape.RightLength ),
1204 getKiCadLength( csPadcode.Shape.Size ) } );
1205
1206 padOffset.x = getKiCadLength( ( (long long) csPadcode.Shape.LeftLength / 2 ) -
1207 ( (long long) csPadcode.Shape.RightLength / 2 ) );
1208 break;
1209
1210
1213 pad->SetSize( PADSTACK::ALL_LAYERS, { getKiCadLength( csPadcode.Shape.Size ),
1214 getKiCadLength( csPadcode.Shape.Size ) } );
1215 break;
1216
1217 default:
1218 wxFAIL_MSG( wxT( "Unknown Pad Shape" ) );
1219 }
1220
1221 if( csPadcode.ReliefClearance != UNDEFINED_VALUE )
1222 pad->SetThermalGap( getKiCadLength( csPadcode.ReliefClearance ) );
1223
1224 if( csPadcode.ReliefWidth != UNDEFINED_VALUE )
1225 pad->SetLocalThermalSpokeWidthOverride( getKiCadLength( csPadcode.ReliefWidth ) );
1226
1227 if( csPadcode.DrillDiameter != UNDEFINED_VALUE )
1228 {
1229 if( csPadcode.SlotLength != UNDEFINED_VALUE )
1230 {
1231 pad->SetDrillShape( PAD_DRILL_SHAPE::OBLONG );
1232 pad->SetDrillSize( { getKiCadLength( (long long) csPadcode.SlotLength +
1233 (long long) csPadcode.DrillDiameter ),
1234 getKiCadLength( csPadcode.DrillDiameter ) } );
1235 }
1236 else
1237 {
1238 pad->SetDrillShape( PAD_DRILL_SHAPE::CIRCLE );
1239 pad->SetDrillSize( { getKiCadLength( csPadcode.DrillDiameter ),
1240 getKiCadLength( csPadcode.DrillDiameter ) } );
1241 }
1242
1243 drillOffset.x = -getKiCadLength( csPadcode.DrillXoffset );
1244 drillOffset.y = getKiCadLength( csPadcode.DrillYoffset );
1245
1246 if( csPadcode.Plated )
1247 pad->SetAttribute( PAD_ATTRIB::PTH );
1248 else
1249 pad->SetAttribute( PAD_ATTRIB::NPTH );
1250 }
1251 else
1252 {
1253 pad->SetDrillSize( { 0, 0 } );
1254 }
1255
1256 if( csPadcode.SlotOrientation != 0 )
1257 {
1258 LSET lset = pad->GetLayerSet();
1259 lset &= LSET::AllCuMask();
1260
1261 if( lset.size() > 0 )
1262 {
1263 SHAPE_POLY_SET padOutline;
1264 PCB_LAYER_ID layer = lset.Seq().at( 0 );
1265 int maxError = m_board->GetDesignSettings().m_MaxError;
1266
1267 pad->SetPosition( { 0, 0 } );
1268 pad->TransformShapeToPolygon( padOutline, layer, 0, maxError, ERROR_INSIDE );
1269
1270 PCB_SHAPE* padShape = new PCB_SHAPE;
1271 padShape->SetShape( SHAPE_T::POLY );
1272 padShape->SetFilled( true );
1273 padShape->SetPolyShape( padOutline );
1274 padShape->SetStroke( STROKE_PARAMS( 0 ) );
1275 padShape->Move( padOffset - drillOffset );
1276 padShape->Rotate( VECTOR2I( 0, 0 ), ANGLE_180 - getAngle( csPadcode.SlotOrientation ) );
1277
1278 SHAPE_POLY_SET editedPadOutline = padShape->GetPolyShape();
1279
1280 if( editedPadOutline.Contains( { 0, 0 } ) )
1281 {
1282 pad->SetAnchorPadShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::RECTANGLE );
1283 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( { 4, 4 } ) );
1285 pad->AddPrimitive( PADSTACK::ALL_LAYERS, padShape );
1286 padOffset = { 0, 0 };
1287 }
1288 else
1289 {
1290 // The CADSTAR pad has the hole shape outside the pad shape
1291 // Lets just put the hole in the center of the pad instead
1292 csPadcode.SlotOrientation = 0;
1293 drillOffset = { 0, 0 };
1294
1295 errorMSG += wxT( "\n - " )
1296 + wxString::Format( _( "The CADSTAR pad definition '%s' has the hole shape outside the "
1297 "pad shape. The hole has been moved to the center of the pad." ),
1298 csPadcode.Name );
1299 }
1300 }
1301 else
1302 {
1303 wxFAIL_MSG( wxT( "No copper layers defined in the pad?" ) );
1304 csPadcode.SlotOrientation = 0;
1305 pad->SetOffset( PADSTACK::ALL_LAYERS, drillOffset );
1306 }
1307 }
1308 else
1309 {
1310 pad->SetOffset( PADSTACK::ALL_LAYERS, drillOffset );
1311 }
1312
1313 EDA_ANGLE padOrientation = getAngle( aCadstarPad.OrientAngle )
1314 + getAngle( csPadcode.Shape.OrientAngle );
1315
1316 RotatePoint( padOffset, padOrientation );
1317 RotatePoint( drillOffset, padOrientation );
1318 pad->SetPosition( getKiCadPoint( aCadstarPad.Position ) - padOffset - drillOffset );
1319 pad->SetOrientation( padOrientation + getAngle( csPadcode.SlotOrientation ) );
1320
1321 //TODO handle csPadcode.Reassigns
1322
1323 //log warnings:
1324 if( m_padcodesTested.find( csPadcode.ID ) == m_padcodesTested.end() && !errorMSG.IsEmpty() )
1325 {
1326 reportError( wxString::Format( _( "The CADSTAR pad definition '%s' has import errors: %s" ),
1327 csPadcode.Name,
1328 errorMSG ) );
1329
1330 m_padcodesTested.insert( csPadcode.ID );
1331 }
1332
1333 return pad.release();
1334}
1335
1336
1338{
1339 size_t index = aCadstarPadID - (long) 1;
1340
1341 if( !( index < aFootprint->Pads().size() ) )
1342 {
1343 THROW_IO_ERRORF( _( "Unable to find pad index '%ld' in footprint '%s'." ),
1344 (long) aCadstarPadID, aFootprint->GetReference() );
1345 }
1346
1347 return aFootprint->Pads().at( index );
1348}
1349
1350
1352{
1353 for( std::pair<GROUP_ID, GROUP> groupPair : Layout.Groups )
1354 {
1355 GROUP& csGroup = groupPair.second;
1356
1357 PCB_GROUP* kiGroup = new PCB_GROUP( m_board );
1358
1359 m_board->Add( kiGroup );
1360 kiGroup->SetName( csGroup.Name );
1361 kiGroup->SetLocked( csGroup.Fixed );
1362
1363 m_groupMap.insert( { csGroup.ID, kiGroup } );
1364 }
1365
1366 //now add any groups to their parent group
1367 for( std::pair<GROUP_ID, GROUP> groupPair : Layout.Groups )
1368 {
1369 GROUP& csGroup = groupPair.second;
1370
1371 if( !csGroup.GroupID.IsEmpty() )
1372 {
1373 if( m_groupMap.find( csGroup.ID ) == m_groupMap.end() )
1374 {
1375 THROW_IO_ERRORF( _( "Unable to find group ID %s in the group definitions." ), csGroup.ID );
1376 }
1377 else if( m_groupMap.find( csGroup.ID ) == m_groupMap.end() )
1378 {
1379 THROW_IO_ERRORF( _( "Unable to find sub group %s in the group map (parent group ID=%s, Name=%s)." ),
1380 csGroup.GroupID,
1381 csGroup.ID,
1382 csGroup.Name );
1383 }
1384 else
1385 {
1386 PCB_GROUP* kiCadGroup = m_groupMap.at( csGroup.ID );
1387 PCB_GROUP* parentGroup = m_groupMap.at( csGroup.GroupID );
1388 parentGroup->AddItem( kiCadGroup );
1389 }
1390 }
1391 }
1392}
1393
1394
1396{
1397 for( std::pair<BOARD_ID, CADSTAR_BOARD> boardPair : Layout.Boards )
1398 {
1399 CADSTAR_BOARD& board = boardPair.second;
1400 GROUP_ID boardGroup = createUniqueGroupID( wxT( "Board" ) );
1401
1403 wxString::Format( wxT( "BOARD %s" ), board.ID ), m_board, boardGroup );
1404
1405 if( !board.GroupID.IsEmpty() )
1406 addToGroup( board.GroupID, getKiCadGroup( boardGroup ) );
1407
1408 //TODO process board attributes when KiCad supports them
1409 }
1410}
1411
1412
1414{
1415 for( std::pair<FIGURE_ID, FIGURE> figPair : Layout.Figures )
1416 {
1417 FIGURE& fig = figPair.second;
1418
1419 for( const PCB_LAYER_ID& layer : getKiCadLayerSet( fig.LayerID ).Seq() )
1420 {
1422 wxString::Format( wxT( "FIGURE %s" ), fig.ID ), m_board, fig.GroupID );
1423 }
1424
1425 //TODO process "swaprule" (doesn't seem to apply to Layout Figures?)
1426 //TODO process re-use block when KiCad Supports it
1427 //TODO process attributes when KiCad Supports attributes in figures
1428 }
1429}
1430
1431
1433{
1434 for( std::pair<TEXT_ID, TEXT> txtPair : Layout.Texts )
1435 {
1436 TEXT& csTxt = txtPair.second;
1437 drawCadstarText( csTxt, m_board );
1438 }
1439}
1440
1441
1443{
1444 for( std::pair<DIMENSION_ID, DIMENSION> dimPair : Layout.Dimensions )
1445 {
1446 DIMENSION& csDim = dimPair.second;
1447
1448 switch( csDim.Type )
1449 {
1450 case DIMENSION::TYPE::LINEARDIM:
1451 switch( csDim.Subtype )
1452 {
1453 case DIMENSION::SUBTYPE::ANGLED:
1454 reportWarning( wxString::Format( _( "Dimension ID %s is an angled dimension, which has no KiCad "
1455 "equivalent. An aligned dimension was loaded instead." ),
1456 csDim.ID ) );
1458 case DIMENSION::SUBTYPE::DIRECT:
1459 case DIMENSION::SUBTYPE::ORTHOGONAL:
1460 {
1461 if( csDim.Line.Style == DIMENSION::LINE::STYLE::EXTERNAL )
1462 {
1463 reportWarning( wxString::Format( _( "Dimension ID %s has 'External' style in CADSTAR. External "
1464 "dimension styles are not yet supported in KiCad. The "
1465 "dimension object was imported with an internal dimension "
1466 "style instead." ),
1467 csDim.ID ) );
1468 }
1469
1470 PCB_DIM_ALIGNED* dimension = nullptr;
1471
1472 if( csDim.Subtype == DIMENSION::SUBTYPE::ORTHOGONAL )
1473 {
1474 dimension = new PCB_DIM_ORTHOGONAL( m_board );
1475 PCB_DIM_ORTHOGONAL* orDim = static_cast<PCB_DIM_ORTHOGONAL*>( dimension );
1476
1477 if( csDim.ExtensionLineParams.Start.x == csDim.Line.Start.x )
1479 else
1481 }
1482 else
1483 {
1484 dimension = new PCB_DIM_ALIGNED( m_board, PCB_DIM_ALIGNED_T );
1485 }
1486
1487 m_board->Add( dimension, ADD_MODE::APPEND );
1488 applyDimensionSettings( csDim, dimension );
1489
1491
1492 // Calculate height:
1493 VECTOR2I crossbarStart = getKiCadPoint( csDim.Line.Start );
1494 VECTOR2I crossbarEnd = getKiCadPoint( csDim.Line.End );
1495 VECTOR2I crossbarVector = crossbarEnd - crossbarStart;
1496 VECTOR2I heightVector = crossbarStart - dimension->GetStart();
1497 double height = 0.0;
1498
1499 if( csDim.Subtype == DIMENSION::SUBTYPE::ORTHOGONAL )
1500 {
1501 if( csDim.ExtensionLineParams.Start.x == csDim.Line.Start.x )
1502 height = heightVector.y;
1503 else
1504 height = heightVector.x;
1505 }
1506 else
1507 {
1508 EDA_ANGLE angle( crossbarVector );
1509 angle += ANGLE_90;
1510 height = heightVector.x * angle.Cos() + heightVector.y * angle.Sin();
1511 }
1512
1513 dimension->SetHeight( height );
1514 }
1515 break;
1516
1517 default:
1518 // Radius and diameter dimensions are LEADERDIM (even if not actually leader)
1519 // Angular dimensions are always ANGLEDIM
1520 reportError( wxString::Format( _( "Unexpected Dimension type (ID %s). This was "
1521 "not imported." ),
1522 csDim.ID ) );
1523 continue;
1524 }
1525 break;
1526
1527 case DIMENSION::TYPE::LEADERDIM:
1528 //TODO: update import when KiCad supports radius and diameter dimensions
1529
1530 if( csDim.Line.Style == DIMENSION::LINE::STYLE::INTERNAL )
1531 {
1532 // "internal" is a simple double sided arrow from start to end (no extension lines)
1534 m_board->Add( dimension, ADD_MODE::APPEND );
1535 applyDimensionSettings( csDim, dimension );
1536
1537 // Lets set again start/end:
1538 dimension->SetStart( getKiCadPoint( csDim.Line.Start ) );
1539 dimension->SetEnd( getKiCadPoint( csDim.Line.End ) );
1540
1541 // Do not use any extension lines:
1542 dimension->SetExtensionOffset( 0 );
1543 dimension->SetExtensionHeight( 0 );
1544 dimension->SetHeight( 0 );
1545 }
1546 else
1547 {
1548 // "external" is a "leader" style dimension
1549 PCB_DIM_LEADER* leaderDim = new PCB_DIM_LEADER( m_board );
1550 m_board->Add( leaderDim, ADD_MODE::APPEND );
1551
1552 applyDimensionSettings( csDim, leaderDim );
1553 leaderDim->SetStart( getKiCadPoint( csDim.Line.End ) );
1554
1555 /*
1556 * In CADSTAR, the resulting shape orientation of the leader dimension depends on
1557 * on the positions of the #Start (S) and #End (E) points as shown below. In the
1558 * diagrams below, the leader angle (angRad) is represented by HEV
1559 *
1560 * Orientation 1: (orientX = -1, | Orientation 2: (orientX = 1,
1561 * orientY = 1) | orientY = 1)
1562 * |
1563 * --------V | V----------
1564 * \ | /
1565 * \ | /
1566 * H _E/ | \E_ H
1567 * |
1568 * S | S
1569 * |
1570 *
1571 * Orientation 3: (orientX = -1, | Orientation 4: (orientX = 1,
1572 * orientY = -1) | orientY = -1)
1573 * |
1574 * S | S
1575 * _ | _
1576 * H E\ | /E H
1577 * / | \
1578 * / | \
1579 * ----------V | V-----------
1580 * |
1581 *
1582 * Corner cases:
1583 *
1584 * It is not possible to generate a leader object with start and end point being
1585 * identical. Assume Orientation 2 if start and end points are identical.
1586 *
1587 * If start and end points are aligned vertically (i.e. S.x == E.x):
1588 * - If E.y > S.y - Orientation 2
1589 * - If E.y < S.y - Orientation 4
1590 *
1591 * If start and end points are aligned horitontally (i.e. S.y == E.y):
1592 * - If E.x > S.x - Orientation 2
1593 * - If E.x < S.x - Orientation 1
1594 */
1595 double angRad = DEG2RAD( getAngleDegrees( csDim.Line.LeaderAngle ) );
1596
1597 double orientX = 1;
1598 double orientY = 1;
1599
1600 if( csDim.Line.End.x >= csDim.Line.Start.x )
1601 {
1602 if( csDim.Line.End.y >= csDim.Line.Start.y )
1603 {
1604 //Orientation 2
1605 orientX = 1;
1606 orientY = 1;
1607 }
1608 else
1609 {
1610 //Orientation 4
1611 orientX = 1;
1612 orientY = -1;
1613 }
1614 }
1615 else
1616 {
1617 if( csDim.Line.End.y >= csDim.Line.Start.y )
1618 {
1619 //Orientation 1
1620 orientX = -1;
1621 orientY = 1;
1622 }
1623 else
1624 {
1625 //Orientation 3
1626 orientX = -1;
1627 orientY = -1;
1628 }
1629 }
1630
1631 VECTOR2I endOffset( csDim.Line.LeaderLineLength * cos( angRad ) * orientX,
1632 csDim.Line.LeaderLineLength * sin( angRad ) * orientY );
1633
1634 VECTOR2I endPoint = VECTOR2I( csDim.Line.End ) + endOffset;
1635 VECTOR2I txtPoint( endPoint.x + ( csDim.Line.LeaderLineExtensionLength * orientX ),
1636 endPoint.y );
1637
1638 leaderDim->SetEnd( getKiCadPoint( endPoint ) );
1639 leaderDim->SetTextPos( getKiCadPoint( txtPoint ) );
1640 leaderDim->SetOverrideText( ParseTextFields( csDim.Text.Text, &m_context ) );
1641 leaderDim->SetPrefix( wxEmptyString );
1642 leaderDim->SetSuffix( wxEmptyString );
1644
1645 if( orientX == 1 )
1647 else
1649
1650 leaderDim->SetExtensionOffset( 0 );
1651 }
1652 break;
1653
1654 case DIMENSION::TYPE::ANGLEDIM:
1655 //TODO: update import when KiCad supports angular dimensions
1656 reportError( wxString::Format( _( "Dimension %s is an angular dimension which has no KiCad equivalent. "
1657 "The object was not imported." ),
1658 csDim.ID ) );
1659 break;
1660 }
1661 }
1662}
1663
1664
1666{
1667 for( std::pair<AREA_ID, AREA> areaPair : Layout.Areas )
1668 {
1669 AREA& area = areaPair.second;
1670
1671 if( area.NoVias || area.NoTracks || area.Keepout || area.Routing )
1672 {
1673 int lineThickness = 0; // CADSTAR areas only use the line width for display purpose
1674 ZONE* zone = getZoneFromCadstarShape( area.Shape, lineThickness, m_board );
1675
1676 m_board->Add( zone, ADD_MODE::APPEND );
1677
1678 if( isLayerSet( area.LayerID ) )
1679 zone->SetLayerSet( getKiCadLayerSet( area.LayerID ) );
1680 else
1681 zone->SetLayer( getKiCadLayer( area.LayerID ) );
1682
1683 zone->SetIsRuleArea( true ); //import all CADSTAR areas as Keepout zones
1684 zone->SetDoNotAllowPads( false ); //no CADSTAR equivalent
1685 zone->SetZoneName( area.Name );
1686
1687 zone->SetDoNotAllowFootprints( area.Keepout );
1688
1689 zone->SetDoNotAllowTracks( area.NoTracks );
1690 zone->SetDoNotAllowZoneFills( area.NoTracks );
1691
1692 zone->SetDoNotAllowVias( area.NoVias );
1693
1694 if( area.Placement )
1695 {
1696 reportWarning( wxString::Format( _( "The CADSTAR area '%s' is marked as a placement area in "
1697 "CADSTAR. Placement areas are not supported in KiCad. Only "
1698 "the supported elements for the area were imported." ),
1699 area.Name ) );
1700 }
1701 }
1702 else
1703 {
1704 reportError( wxString::Format( _( "The CADSTAR area '%s' does not have a KiCad equivalent. Pure "
1705 "Placement areas are not supported." ),
1706 area.Name ) );
1707 }
1708
1709 //todo Process area.AreaHeight when KiCad supports 3D design rules
1710 //TODO process attributes
1711 //TODO process addition to a group
1712 //TODO process "swaprule"
1713 //TODO process re-use block
1714 }
1715}
1716
1717
1719{
1720 for( std::pair<COMPONENT_ID, COMPONENT> compPair : Layout.Components )
1721 {
1722 COMPONENT& comp = compPair.second;
1723
1724 if( !comp.VariantID.empty() && comp.VariantParentComponentID != comp.ID )
1725 continue; // Only load master Variant
1726
1727 auto fpIter = m_libraryMap.find( comp.SymdefID );
1728
1729 if( fpIter == m_libraryMap.end() )
1730 {
1731 THROW_IO_ERRORF( _( "Unable to find component '%s' in the library (Symdef ID: '%s')" ),
1732 comp.Name, comp.SymdefID );
1733 }
1734
1735 FOOTPRINT* libFootprint = fpIter->second;
1736
1737 // Use Duplicate() to ensure unique KIID for all objects
1738 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( libFootprint->Duplicate( IGNORE_PARENT_GROUP ) );
1739
1740 m_board->Add( footprint, ADD_MODE::APPEND );
1741
1742 // First lets fix the pad names on the footprint.
1743 // CADSTAR defines the pad name in the PART definition and the SYMDEF (i.e. the PCB
1744 // footprint definition) uses a numerical sequence. COMP is the only object that has
1745 // visibility of both the SYMDEF and PART.
1746 if( Parts.PartDefinitions.find( comp.PartID ) != Parts.PartDefinitions.end() )
1747 {
1748 PART part = Parts.PartDefinitions.at( comp.PartID );
1749
1750 // Only do this when the number of pins in the part definition equals the number of
1751 // pads in the footprint.
1752 if( part.Definition.Pins.size() == footprint->Pads().size() )
1753 {
1754 for( std::pair<PART_DEFINITION_PIN_ID, PART::DEFINITION::PIN> pinPair :
1755 part.Definition.Pins )
1756 {
1757 PART::DEFINITION::PIN pin = pinPair.second;
1758 wxString pinName = pin.Name;
1759
1760 if( pinName.empty() )
1761 pinName = pin.Identifier;
1762
1763 if( pinName.empty() )
1764 pinName = wxString::Format( wxT( "%ld" ), pin.ID );
1765
1766 getPadReference( footprint, pin.ID )->SetNumber( pinName );
1767 }
1768 }
1769 }
1770
1771 //Override pads with pad exceptions
1772 if( comp.PadExceptions.size() > 0 )
1773 {
1774 SYMDEF_PCB fpLibEntry = Library.ComponentDefinitions.at( comp.SymdefID );
1775
1776 for( std::pair<PAD_ID, PADEXCEPTION> padPair : comp.PadExceptions )
1777 {
1778 PADEXCEPTION& padEx = padPair.second;
1779 COMPONENT_PAD csPad = fpLibEntry.ComponentPads.at( padPair.first );
1780
1781 // Reset the pad to be around 0,0
1782 csPad.Position -= fpLibEntry.Origin;
1783 csPad.Position += m_designCenter;
1784
1785 if( !padEx.PadCode.IsEmpty() )
1786 csPad.PadCodeID = padEx.PadCode;
1787
1788 if( padEx.OverrideExits )
1789 csPad.Exits = padEx.Exits;
1790
1791 if( padEx.OverrideOrientation )
1792 csPad.OrientAngle = padEx.OrientAngle;
1793
1794 if( padEx.OverrideSide )
1795 csPad.Side = padEx.Side;
1796
1797 // Find the pad in the footprint definition
1798 PAD* kiPad = getPadReference( footprint, padEx.ID );
1799
1800 wxString padNumber = kiPad->GetNumber();
1801
1802 delete kiPad;
1803
1804 if( ( kiPad = getKiCadPad( csPad, footprint ) ) )
1805 {
1806 kiPad->SetNumber( padNumber );
1807
1808 // Change the pointer in the footprint to the newly created pad
1809 getPadReference( footprint, padEx.ID ) = kiPad;
1810 }
1811 }
1812 }
1813
1814 //set to empty string to avoid duplication when loading attributes:
1815 footprint->SetValue( wxEmptyString );
1816
1817 footprint->SetPosition( getKiCadPoint( comp.Origin ) );
1818 footprint->SetOrientation( getAngle( comp.OrientAngle ) );
1819 footprint->SetReference( comp.Name );
1820
1821 if( comp.Mirror )
1822 {
1823 EDA_ANGLE mirroredAngle = - getAngle( comp.OrientAngle );
1824 mirroredAngle.Normalize180();
1825 footprint->SetOrientation( mirroredAngle );
1826 footprint->Flip( getKiCadPoint( comp.Origin ), FLIP_DIRECTION::LEFT_RIGHT );
1827 }
1828
1829 loadComponentAttributes( comp, footprint );
1830
1831 if( !comp.PartID.IsEmpty() && comp.PartID != wxT( "NO_PART" ) )
1832 footprint->SetLibDescription( getPart( comp.PartID ).Definition.Name );
1833
1834 m_componentMap.insert( { comp.ID, footprint } );
1835 }
1836}
1837
1838
1840{
1841 //No KiCad equivalent. Loaded as graphic and text elements instead
1842
1843 for( std::pair<DOCUMENTATION_SYMBOL_ID, DOCUMENTATION_SYMBOL> docPair : Layout.DocumentationSymbols )
1844 {
1845 DOCUMENTATION_SYMBOL& docSymInstance = docPair.second;
1846
1847
1848 auto docSymIter = Library.ComponentDefinitions.find( docSymInstance.SymdefID );
1849
1850 if( docSymIter == Library.ComponentDefinitions.end() )
1851 {
1852 THROW_IO_ERRORF( _( "Unable to find documentation symbol in the library (Symdef ID: '%s')" ),
1853 docSymInstance.SymdefID );
1854 }
1855
1856 SYMDEF_PCB& docSymDefinition = ( *docSymIter ).second;
1857 VECTOR2I moveVector = getKiCadPoint( docSymInstance.Origin ) - getKiCadPoint( docSymDefinition.Origin );
1858 double rotationAngle = getAngleTenthDegree( docSymInstance.OrientAngle );
1859 double scalingFactor = (double) docSymInstance.ScaleRatioNumerator
1860 / (double) docSymInstance.ScaleRatioDenominator;
1861 VECTOR2I centreOfTransform = getKiCadPoint( docSymDefinition.Origin );
1862 bool mirrorInvert = docSymInstance.Mirror;
1863
1864 //create a group to store the items in
1865 wxString groupName = docSymDefinition.ReferenceName;
1866
1867 if( !docSymDefinition.Alternate.IsEmpty() )
1868 groupName += wxT( " (" ) + docSymDefinition.Alternate + wxT( ")" );
1869
1870 GROUP_ID groupID = createUniqueGroupID( groupName );
1871
1872 LSEQ layers = getKiCadLayerSet( docSymInstance.LayerID ).Seq();
1873
1874 for( PCB_LAYER_ID layer : layers )
1875 {
1876 for( std::pair<FIGURE_ID, FIGURE> figPair : docSymDefinition.Figures )
1877 {
1878 FIGURE fig = figPair.second;
1880 wxString::Format( wxT( "DOCUMENTATION SYMBOL %s, FIGURE %s" ),
1881 docSymDefinition.ReferenceName, fig.ID ),
1882 m_board, groupID, moveVector, rotationAngle, scalingFactor,
1883 centreOfTransform, mirrorInvert );
1884 }
1885 }
1886
1887 for( std::pair<TEXT_ID, TEXT> textPair : docSymDefinition.Texts )
1888 {
1889 TEXT txt = textPair.second;
1890 drawCadstarText( txt, m_board, groupID, docSymInstance.LayerID, moveVector, rotationAngle,
1891 scalingFactor, centreOfTransform, mirrorInvert );
1892 }
1893 }
1894}
1895
1896
1898{
1899 for( std::pair<TEMPLATE_ID, TEMPLATE> tempPair : Layout.Templates )
1900 {
1901 TEMPLATE& csTemplate = tempPair.second;
1902
1903 int zonelinethickness = 0; // The line thickness in CADSTAR is only for display purposes but
1904 // does not affect the end copper result.
1905 ZONE* zone = getZoneFromCadstarShape( csTemplate.Shape, zonelinethickness, m_board );
1906
1907 m_board->Add( zone, ADD_MODE::APPEND );
1908
1909 zone->SetZoneName( csTemplate.Name );
1910 zone->SetLayer( getKiCadLayer( csTemplate.LayerID ) );
1911 zone->SetAssignedPriority( 1 ); // initially 1, we will increase in calculateZonePriorities
1912
1913 if( !( csTemplate.NetID.IsEmpty() || csTemplate.NetID == wxT( "NONE" ) ) )
1914 zone->SetNet( getKiCadNet( csTemplate.NetID ) );
1915
1916 if( csTemplate.Pouring.AllowInNoRouting )
1917 {
1918 reportWarning( wxString::Format( _( "The CADSTAR template '%s' has the setting 'Allow in No Routing "
1919 "Areas' enabled. This setting has no KiCad equivalent, so it has "
1920 "been ignored." ),
1921 csTemplate.Name ) );
1922 }
1923
1924 if( csTemplate.Pouring.BoxIsolatedPins )
1925 {
1926 reportWarning( wxString::Format( _( "The CADSTAR template '%s' has the setting 'Box Isolated Pins' "
1927 "enabled. This setting has no KiCad equivalent, so it has been "
1928 "ignored." ),
1929 csTemplate.Name ) );
1930 }
1931
1932 if( csTemplate.Pouring.AutomaticRepour )
1933 {
1934 reportWarning( wxString::Format( _( "The CADSTAR template '%s' has the setting 'Automatic Repour' "
1935 "enabled. This setting has no KiCad equivalent, so it has been "
1936 "ignored." ),
1937 csTemplate.Name ) );
1938 }
1939
1940 // Sliver width has different behaviour to KiCad Zone's minimum thickness
1941 // In Cadstar 'Sliver width' has to be greater than the Copper thickness, whereas in
1942 // Kicad it is the opposite.
1943 if( csTemplate.Pouring.SliverWidth != 0 )
1944 {
1945 reportWarning( wxString::Format(
1946 _( "The CADSTAR template '%s' has a non-zero value defined for the "
1947 "'Sliver Width' setting. There is no KiCad equivalent for "
1948 "this, so this setting was ignored." ),
1949 csTemplate.Name ) );
1950 }
1951
1952
1953 if( csTemplate.Pouring.MinIsolatedCopper != csTemplate.Pouring.MinDisjointCopper )
1954 {
1955 reportWarning( wxString::Format(
1956 _( "The CADSTAR template '%s' has different settings for 'Retain Poured Copper "
1957 "- Disjoint' and 'Retain Poured Copper - Isolated'. KiCad does not "
1958 "distinguish between these two settings. The setting for disjoint copper "
1959 "has been applied as the minimum island area of the KiCad Zone." ),
1960 csTemplate.Name ) );
1961 }
1962
1963 long long minIslandArea = -1;
1964
1965 if( csTemplate.Pouring.MinDisjointCopper != UNDEFINED_VALUE )
1966 {
1967 minIslandArea = (long long) getKiCadLength( csTemplate.Pouring.MinDisjointCopper )
1968 * (long long) getKiCadLength( csTemplate.Pouring.MinDisjointCopper );
1969
1971 }
1972 else
1973 {
1975 }
1976
1977 zone->SetMinIslandArea( minIslandArea );
1978
1979 // In cadstar zone clearance is in addition to the global clearance.
1980 // TODO: need to create custom rules for individual items: zone to pad, zone to track, etc.
1982 clearance += m_board->GetDesignSettings().m_MinClearance;
1983
1985
1986 COPPERCODE pouringCopperCode = getCopperCode( csTemplate.Pouring.CopperCodeID );
1987 int minThickness = getKiCadLength( pouringCopperCode.CopperWidth );
1988 zone->SetMinThickness( minThickness );
1989
1990 if( csTemplate.Pouring.FillType == TEMPLATE::POURING::COPPER_FILL_TYPE::HATCHED )
1991 {
1993 zone->SetHatchGap( getKiCadHatchCodeGap( csTemplate.Pouring.HatchCodeID ) );
1996 }
1997 else
1998 {
2000 }
2001
2002 if( csTemplate.Pouring.ThermalReliefOnPads != csTemplate.Pouring.ThermalReliefOnVias
2003 || csTemplate.Pouring.ThermalReliefPadsAngle
2004 != csTemplate.Pouring.ThermalReliefViasAngle )
2005 {
2006 reportWarning( wxString::Format(
2007 _( "The CADSTAR template '%s' has different settings for thermal relief "
2008 "in pads and vias. KiCad only supports one single setting for both. The "
2009 "setting for pads has been applied." ),
2010 csTemplate.Name ) );
2011 }
2012
2013 COPPERCODE reliefCopperCode = getCopperCode( csTemplate.Pouring.ReliefCopperCodeID );
2014 int spokeWidth = getKiCadLength( reliefCopperCode.CopperWidth );
2015 int reliefWidth = getKiCadLength( csTemplate.Pouring.ClearanceWidth );
2016
2017 // Cadstar supports having a spoke width thinner than the minimum thickness of the zone, but
2018 // this is not permitted in KiCad. We load it as solid fill instead.
2019 if( csTemplate.Pouring.ThermalReliefOnPads && reliefWidth > 0 )
2020 {
2021 if( spokeWidth < minThickness )
2022 {
2023 reportWarning( wxString::Format(
2024 _( "The CADSTAR template '%s' has thermal reliefs in the original design "
2025 "but the spoke width (%.2f mm) is thinner than the minimum thickness of " //format:allow
2026 "the zone (%.2f mm). KiCad requires the minimum thickness of the zone " //format:allow
2027 "to be preserved. Therefore the minimum thickness has been applied as "
2028 "the new spoke width and will be applied next time the zones are "
2029 "filled." ),
2030 csTemplate.Name, (double) getKiCadLength( spokeWidth ) / 1E6,
2031 (double) getKiCadLength( minThickness ) / 1E6 ) );
2032
2033 spokeWidth = minThickness;
2034 }
2035
2036 zone->SetThermalReliefGap( reliefWidth );
2037 zone->SetThermalReliefSpokeWidth( spokeWidth );
2039 }
2040 else
2041 {
2043 }
2044
2045 m_zonesMap.insert( { csTemplate.ID, zone } );
2046 }
2047
2048 //Now create power plane layers:
2049 for( LAYER_ID layer : m_powerPlaneLayers )
2050 {
2051 wxASSERT( Assignments.Layerdefs.Layers.find( layer ) != Assignments.Layerdefs.Layers.end() );
2052
2053 //The net name will equal the layer name
2054 wxString powerPlaneLayerName = Assignments.Layerdefs.Layers.at( layer ).Name;
2055 NET_ID netid = wxEmptyString;
2056
2057 for( std::pair<NET_ID, NET_PCB> netPair : Layout.Nets )
2058 {
2059 NET_PCB net = netPair.second;
2060
2061 if( net.Name == powerPlaneLayerName )
2062 {
2063 netid = net.ID;
2064 break;
2065 }
2066 }
2067
2068 if( netid.IsEmpty() )
2069 {
2070 reportError( wxString::Format( _( "The CADSTAR layer '%s' is defined as a power "
2071 "plane layer. However no net with such name "
2072 "exists. The layer has been loaded but no copper "
2073 "zone was created." ),
2074 powerPlaneLayerName ) );
2075 }
2076 else
2077 {
2078 for( std::pair<BOARD_ID, CADSTAR_BOARD> boardPair : Layout.Boards )
2079 {
2080 //create a zone in each board shape
2081 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
2082 CADSTAR_BOARD& board = boardPair.second;
2083 int defaultLineThicknesss = bds.GetLineThickness( PCB_LAYER_ID::Edge_Cuts );
2084 ZONE* zone = getZoneFromCadstarShape( board.Shape, defaultLineThicknesss, m_board );
2085
2086 m_board->Add( zone, ADD_MODE::APPEND );
2087
2088 zone->SetZoneName( powerPlaneLayerName );
2089 zone->SetLayer( getKiCadLayer( layer ) );
2092 zone->SetMinIslandArea( -1 );
2093 zone->SetAssignedPriority( 0 ); // Priority always 0 (lowest priority) for implied power planes.
2094 zone->SetNet( getKiCadNet( netid ) );
2095 }
2096 }
2097 }
2098}
2099
2100
2102{
2103 for( std::pair<COPPER_ID, COPPER> copPair : Layout.Coppers )
2104 {
2105 COPPER& csCopper = copPair.second;
2106
2107 checkPoint();
2108
2109 if( !csCopper.PouredTemplateID.IsEmpty() )
2110 {
2111 ZONE* pouredZone = m_zonesMap.at( csCopper.PouredTemplateID );
2112 SHAPE_POLY_SET fill;
2113
2114 int copperWidth = getKiCadLength( getCopperCode( csCopper.CopperCodeID ).CopperWidth );
2115
2116 if( csCopper.Shape.Type == SHAPE_TYPE::OPENSHAPE )
2117 {
2118 // This is usually for themal reliefs. They are lines of copper with a thickness.
2119 // We convert them to an oval in most cases, but handle also the possibility of
2120 // encountering arcs in here.
2121
2122 std::vector<PCB_SHAPE*> outlineShapes = getShapesFromVertices( csCopper.Shape.Vertices );
2123
2124 for( PCB_SHAPE* shape : outlineShapes )
2125 {
2126 SHAPE_POLY_SET poly;
2127
2128 if( shape->GetShape() == SHAPE_T::ARC )
2129 {
2130 TransformArcToPolygon( poly, shape->GetStart(), shape->GetArcMid(), shape->GetEnd(),
2131 copperWidth, ARC_HIGH_DEF, ERROR_LOC::ERROR_INSIDE );
2132 }
2133 else
2134 {
2135 TransformOvalToPolygon( poly, shape->GetStart(), shape->GetEnd(), copperWidth,
2137 }
2138
2139 poly.ClearArcs();
2140 fill.BooleanAdd( poly );
2141 }
2142
2143 }
2144 else
2145 {
2146 fill = getPolySetFromCadstarShape( csCopper.Shape, -1 );
2147 fill.ClearArcs();
2149 }
2150
2151 if( pouredZone->HasFilledPolysForLayer( getKiCadLayer( csCopper.LayerID ) ) )
2152 fill.BooleanAdd( *pouredZone->GetFill( getKiCadLayer( csCopper.LayerID ) ) );
2153
2154 fill.Fracture();
2155
2156 pouredZone->SetFilledPolysList( getKiCadLayer( csCopper.LayerID ), fill );
2157 pouredZone->SetIsFilled( true );
2158 pouredZone->SetNeedRefill( false );
2159 continue;
2160 }
2161
2162 // For now we are going to load coppers to a KiCad zone however this isn't perfect
2163 //TODO: Load onto a graphical polygon with a net
2164
2165 if( !m_doneCopperWarning )
2166 {
2167 reportWarning( _( "The CADSTAR design contains COPPER elements, which have no direct KiCad "
2168 "equivalent. These have been imported as a KiCad Zone if solid or hatch "
2169 "filled, or as a KiCad Track if the shape was an unfilled outline (open or "
2170 "closed)." ) );
2171 m_doneCopperWarning = true;
2172 }
2173
2174
2175 if( csCopper.Shape.Type == SHAPE_TYPE::OPENSHAPE
2176 || csCopper.Shape.Type == SHAPE_TYPE::OUTLINE )
2177 {
2178 std::vector<PCB_SHAPE*> outlineShapes = getShapesFromVertices( csCopper.Shape.Vertices );
2179
2180 std::vector<PCB_TRACK*> outlineTracks = makeTracksFromShapes( outlineShapes, m_board,
2181 getKiCadNet( csCopper.NetRef.NetID ),
2182 getKiCadLayer( csCopper.LayerID ),
2184
2185 //cleanup
2186 for( PCB_SHAPE* shape : outlineShapes )
2187 delete shape;
2188
2189 for( const CUTOUT& cutout : csCopper.Shape.Cutouts )
2190 {
2191 std::vector<PCB_SHAPE*> cutoutShapes = getShapesFromVertices( cutout.Vertices );
2192
2193 std::vector<PCB_TRACK*> cutoutTracks = makeTracksFromShapes( cutoutShapes, m_board,
2194 getKiCadNet( csCopper.NetRef.NetID ),
2195 getKiCadLayer( csCopper.LayerID ),
2197
2198 //cleanup
2199 for( PCB_SHAPE* shape : cutoutShapes )
2200 delete shape;
2201 }
2202 }
2203 else
2204 {
2205 ZONE* zone = getZoneFromCadstarShape( csCopper.Shape,
2207 m_board );
2208
2209 m_board->Add( zone, ADD_MODE::APPEND );
2210
2211 zone->SetZoneName( csCopper.ID );
2212 zone->SetLayer( getKiCadLayer( csCopper.LayerID ) );
2214
2215 if( csCopper.Shape.Type == SHAPE_TYPE::HATCHED )
2216 {
2221 }
2222 else
2223 {
2225 }
2226
2229 zone->SetNet( getKiCadNet( csCopper.NetRef.NetID ) );
2230 zone->SetAssignedPriority( m_zonesMap.size() + 1 ); // Highest priority (always fill first)
2231
2232 SHAPE_POLY_SET fill( *zone->Outline() );
2233 fill.Fracture();
2234
2235 zone->SetFilledPolysList( getKiCadLayer( csCopper.LayerID ), fill );
2236 }
2237 }
2238}
2239
2240
2242{
2243 for( std::pair<NET_ID, NET_PCB> netPair : Layout.Nets )
2244 {
2245 NET_PCB net = netPair.second;
2246 wxString netnameForErrorReporting = net.Name;
2247
2248 std::map<NETELEMENT_ID, long> netelementSizes;
2249
2250 if( netnameForErrorReporting.IsEmpty() )
2251 netnameForErrorReporting = wxString::Format( wxT( "$%ld" ), net.SignalNum );
2252
2253 for( std::pair<NETELEMENT_ID, NET_PCB::VIA> viaPair : net.Vias )
2254 {
2255 NET_PCB::VIA via = viaPair.second;
2256
2257 // viasize is used for calculating route offset (as done in CADSTAR post processor)
2258 int viaSize = loadNetVia( net.ID, via );
2259 netelementSizes.insert( { viaPair.first, viaSize } );
2260 }
2261
2262 for( std::pair<NETELEMENT_ID, NET_PCB::PIN> pinPair : net.Pins )
2263 {
2264 NET_PCB::PIN pin = pinPair.second;
2265 FOOTPRINT* footprint = getFootprintFromCadstarID( pin.ComponentID );
2266
2267 if( footprint == nullptr )
2268 {
2269 reportWarning( wxString::Format( _( "The net '%s' references component ID '%s' which does not exist. "
2270 "This has been ignored." ),
2271 netnameForErrorReporting, pin.ComponentID ) );
2272 }
2273 else if( pin.PadID <= 0
2274 || static_cast<size_t>( pin.PadID ) > footprint->Pads().size() )
2275 {
2276 // Pad IDs are one-based, so the valid range is [1, Pads().size()]. Anything
2277 // else would throw out of getPadReference() and abort the whole import.
2278 reportWarning( wxString::Format( _( "The net '%s' references non-existent pad "
2279 "index '%ld' in component '%s'. This has "
2280 "been ignored." ),
2281 netnameForErrorReporting,
2282 pin.PadID,
2283 footprint->GetReference() ) );
2284 }
2285 else
2286 {
2287 // The below works because we have added the pads in the correct order to the
2288 // footprint and the PAD_ID in Cadstar is a sequential, numerical ID
2289 PAD* pad = getPadReference( footprint, pin.PadID );
2290 pad->SetNet( getKiCadNet( net.ID ) );
2291
2292 // also set the net to any copper pads (i.e. copper elements that we have imported
2293 // as pads instead:
2294 SYMDEF_ID symdefid = Layout.Components.at( pin.ComponentID ).SymdefID;
2295
2296 if( m_librarycopperpads.find( symdefid ) != m_librarycopperpads.end() )
2297 {
2298 ASSOCIATED_COPPER_PADS assocPads = m_librarycopperpads.at( symdefid );
2299
2300 if( assocPads.find( pin.PadID ) != assocPads.end() )
2301 {
2302 for( PAD_ID copperPadID : assocPads.at( pin.PadID ) )
2303 {
2304 PAD* copperpad = getPadReference( footprint, copperPadID );
2305 copperpad->SetNet( getKiCadNet( net.ID ) );
2306 }
2307 }
2308 }
2309
2310 // padsize is used for calculating route offset (as done in CADSTAR post processor)
2311 int padsize = std::min( pad->GetSizeX(), pad->GetSizeY() );
2312 netelementSizes.insert( { pinPair.first, padsize } );
2313 }
2314 }
2315
2316 // For junction points we need to find out the biggest size of the other routes connecting
2317 // at the junction in order to correctly apply the same "route offset" operation that the
2318 // CADSTAR post processor applies when generating Manufacturing output. The only exception
2319 // is if there is just a single route at the junction point, we use that route width
2320 // Optimal width of a route code, falling back to the default netclass track width when the
2321 // route code is missing or specifies no usable width. Unlike getRouteCode() this tolerates
2322 // an absent route code silently, as expected for CADSTAR Revision 7 routes that omit
2323 // ROUTEWIDTH, and never yields a non-positive track width.
2324 auto getRouteCodeWidth =
2325 [&]( const ROUTECODE_ID& aRouteCodeID ) -> long
2326 {
2327 auto rcIt = Assignments.Codedefs.RouteCodes.find( aRouteCodeID );
2328
2329 if( rcIt != Assignments.Codedefs.RouteCodes.end() && rcIt->second.OptimalWidth > 0 )
2330 return rcIt->second.OptimalWidth;
2331
2332 long defaultWidth =
2333 m_board->GetDesignSettings().m_NetSettings->GetDefaultNetclass()->GetTrackWidth();
2334
2335 return defaultWidth / KiCadUnitMultiplier;
2336 };
2337
2338 // Resolve a vertex width, falling back to the connection's route code when the
2339 // ROUTEWIDTH node was omitted (CADSTAR Revision 7 format).
2340 auto getVertexWidth =
2341 [&]( const NET_PCB::ROUTE_VERTEX& aVertex, const ROUTECODE_ID& aRouteCodeID ) -> long
2342 {
2343 if( aVertex.RouteWidthIsExplicit )
2344 return aVertex.RouteWidth;
2345
2346 return getRouteCodeWidth( aRouteCodeID );
2347 };
2348
2349 auto getJunctionSize =
2350 [&]( const NETELEMENT_ID& aJptNetElemId, const NET_PCB::CONNECTION_PCB& aConnectionToIgnore ) -> int
2351 {
2352 int jptsize = std::numeric_limits<int>::max();
2353
2354 for( NET_PCB::CONNECTION_PCB connection : net.Connections )
2355 {
2356 if( connection.Route.RouteVertices.size() == 0 )
2357 continue;
2358
2359 if( connection.StartNode == aConnectionToIgnore.StartNode
2360 && connection.EndNode == aConnectionToIgnore.EndNode )
2361 {
2362 continue;
2363 }
2364
2365 if( connection.StartNode == aJptNetElemId )
2366 {
2367 int s = getKiCadLength( getVertexWidth( connection.Route.RouteVertices.front(),
2368 connection.RouteCodeID ) );
2369 jptsize = std::max( jptsize, s );
2370 }
2371 else if( connection.EndNode == aJptNetElemId )
2372 {
2373 int s = getKiCadLength( getVertexWidth( connection.Route.RouteVertices.back(),
2374 connection.RouteCodeID ) );
2375 jptsize = std::max( jptsize, s );
2376 }
2377 }
2378
2379 if( jptsize == std::numeric_limits<int>::max()
2380 && !aConnectionToIgnore.Route.RouteVertices.empty() )
2381 {
2382 // aConnectionToIgnore is actually the only one that has a route, so lets use that
2383 // to determine junction size
2384 NET_PCB::ROUTE_VERTEX vertex = aConnectionToIgnore.Route.RouteVertices.front();
2385
2386 if( aConnectionToIgnore.EndNode == aJptNetElemId )
2387 vertex = aConnectionToIgnore.Route.RouteVertices.back();
2388
2389 jptsize = getKiCadLength( getVertexWidth( vertex, aConnectionToIgnore.RouteCodeID ) );
2390 }
2391
2392 return jptsize;
2393 };
2394
2395 for( const NET_PCB::CONNECTION_PCB& connection : net.Connections )
2396 {
2397 int startSize = std::numeric_limits<int>::max();
2398 int endSize = std::numeric_limits<int>::max();
2399
2400 if( netelementSizes.find( connection.StartNode ) != netelementSizes.end() )
2401 startSize = netelementSizes.at( connection.StartNode );
2402 else if( net.Junctions.find( connection.StartNode ) != net.Junctions.end() )
2403 startSize = getJunctionSize( connection.StartNode, connection );
2404
2405 if( netelementSizes.find( connection.EndNode ) != netelementSizes.end() )
2406 endSize = netelementSizes.at( connection.EndNode );
2407 else if( net.Junctions.find( connection.EndNode ) != net.Junctions.end() )
2408 endSize = getJunctionSize( connection.EndNode, connection );
2409
2410 startSize /= KiCadUnitMultiplier;
2411 endSize /= KiCadUnitMultiplier;
2412
2413 if( !connection.Unrouted )
2414 {
2415 loadNetTracks( net.ID, connection.Route, getRouteCodeWidth( connection.RouteCodeID ),
2416 startSize, endSize );
2417 }
2418 }
2419 }
2420}
2421
2422
2424{
2425 auto findAndReplaceTextField =
2426 [&]( TEXT_FIELD_NAME aField, wxString aValue )
2427 {
2428 if( m_context.TextFieldToValuesMap.find( aField ) != m_context.TextFieldToValuesMap.end() )
2429 {
2430 if( m_context.TextFieldToValuesMap.at( aField ) != aValue )
2431 {
2432 m_context.TextFieldToValuesMap.at( aField ) = aValue;
2433 m_context.InconsistentTextFields.insert( aField );
2434 return false;
2435 }
2436 }
2437 else
2438 {
2439 m_context.TextFieldToValuesMap.insert( { aField, aValue } );
2440 }
2441
2442 return true;
2443 };
2444
2445 if( m_project )
2446 {
2447 std::map<wxString, wxString>& txtVars = m_project->GetTextVars();
2448
2449 // Most of the design text fields can be derived from other elements
2450 if( Layout.VariantHierarchy.Variants.size() > 0 )
2451 {
2452 VARIANT loadedVar = Layout.VariantHierarchy.Variants.begin()->second;
2453
2454 findAndReplaceTextField( TEXT_FIELD_NAME::VARIANT_NAME, loadedVar.Name );
2455 findAndReplaceTextField( TEXT_FIELD_NAME::VARIANT_DESCRIPTION, loadedVar.Description );
2456 }
2457
2458 findAndReplaceTextField( TEXT_FIELD_NAME::DESIGN_TITLE, Header.JobTitle );
2459
2460 for( std::pair<TEXT_FIELD_NAME, wxString> txtvalue : m_context.TextFieldToValuesMap )
2461 {
2462 wxString varName = CADSTAR_TO_KICAD_FIELDS.at( txtvalue.first );
2463 wxString varValue = txtvalue.second;
2464
2465 txtVars.insert( { varName, varValue } );
2466 }
2467
2468 for( std::pair<wxString, wxString> txtvalue : m_context.FilenamesToTextMap )
2469 {
2470 wxString varName = txtvalue.first;
2471 wxString varValue = txtvalue.second;
2472
2473 txtVars.insert( { varName, varValue } );
2474 }
2475 }
2476 else
2477 {
2478 reportError( _( "Text Variables could not be set as there is no project loaded." ) );
2479 }
2480}
2481
2482
2484 FOOTPRINT* aFootprint )
2485{
2486 for( std::pair<ATTRIBUTE_ID, ATTRIBUTE_VALUE> attrPair : aComponent.AttributeValues )
2487 {
2488 ATTRIBUTE_VALUE& attrval = attrPair.second;
2489
2490 if( attrval.HasLocation ) //only import attributes with location. Ignore the rest
2491 addAttribute( attrval.AttributeLocation, attrval.AttributeID, aFootprint, attrval.Value );
2492 }
2493
2494 for( std::pair<ATTRIBUTE_ID, TEXT_LOCATION> textlocPair : aComponent.TextLocations )
2495 {
2496 TEXT_LOCATION& textloc = textlocPair.second;
2497 wxString attrval;
2498
2499 if( textloc.AttributeID == COMPONENT_NAME_ATTRID )
2500 attrval = wxEmptyString; // Designator is loaded separately
2501 else if( textloc.AttributeID == COMPONENT_NAME_2_ATTRID )
2502 attrval = wxT( "${REFERENCE}" );
2503 else if( textloc.AttributeID == PART_NAME_ATTRID )
2504 attrval = getPart( aComponent.PartID ).Name;
2505 else
2506 attrval = getAttributeValue( textloc.AttributeID, aComponent.AttributeValues );
2507
2508 addAttribute( textloc, textloc.AttributeID, aFootprint, attrval );
2509 }
2510}
2511
2512
2514 const NET_PCB::ROUTE& aCadstarRoute,
2515 long aDefaultRouteWidth,
2516 long aStartWidth, long aEndWidth )
2517{
2518 if( aCadstarRoute.RouteVertices.size() == 0 )
2519 return;
2520
2521 std::vector<PCB_SHAPE*> shapes;
2522 std::vector<NET_PCB::ROUTE_VERTEX> routeVertices = aCadstarRoute.RouteVertices;
2523
2524 // Fill in default route width for vertices that don't have explicit widths (CADSTAR Revision 7)
2525 for( NET_PCB::ROUTE_VERTEX& v : routeVertices )
2526 {
2527 if( !v.RouteWidthIsExplicit )
2528 v.RouteWidth = aDefaultRouteWidth;
2529 }
2530
2531 // Add thin route at front so that route offsetting works as expected
2532 if( aStartWidth < routeVertices.front().RouteWidth )
2533 {
2534 NET_PCB::ROUTE_VERTEX newFrontVertex = aCadstarRoute.RouteVertices.front();
2535 newFrontVertex.RouteWidth = aStartWidth;
2536 newFrontVertex.Vertex.End = aCadstarRoute.StartPoint;
2537 routeVertices.insert( routeVertices.begin(), newFrontVertex );
2538 }
2539
2540 // Add thin route at the back if required
2541 if( aEndWidth < routeVertices.back().RouteWidth )
2542 {
2543 NET_PCB::ROUTE_VERTEX newBackVertex = aCadstarRoute.RouteVertices.back();
2544 newBackVertex.RouteWidth = aEndWidth;
2545 routeVertices.push_back( newBackVertex );
2546 }
2547
2548 POINT prevEnd = aCadstarRoute.StartPoint;
2549
2550 for( const NET_PCB::ROUTE_VERTEX& v : routeVertices )
2551 {
2552 PCB_SHAPE* shape = getShapeFromVertex( prevEnd, v.Vertex );
2553 shape->SetLayer( getKiCadLayer( aCadstarRoute.LayerID ) );
2554 shape->SetStroke( STROKE_PARAMS( getKiCadLength( v.RouteWidth ), LINE_STYLE::SOLID ) );
2555 shape->SetLocked( v.Fixed );
2556 shapes.push_back( shape );
2557 prevEnd = v.Vertex.End;
2558
2559 if( !m_doneTearDropWarning && ( v.TeardropAtEnd || v.TeardropAtStart ) )
2560 {
2561 // TODO: load teardrops
2562 reportError( _( "The CADSTAR design contains teardrops. This importer does not yet "
2563 "support them, so the teardrops in the design have been ignored." ) );
2564
2565 m_doneTearDropWarning = true;
2566 }
2567 }
2568
2569 NETINFO_ITEM* net = getKiCadNet( aCadstarNetID );
2570 std::vector<PCB_TRACK*> tracks = makeTracksFromShapes( shapes, m_board, net );
2571
2572 //cleanup
2573 for( PCB_SHAPE* shape : shapes )
2574 delete shape;
2575}
2576
2577
2578int CADSTAR_PCB_ARCHIVE_LOADER::loadNetVia( const NET_ID& aCadstarNetID, const NET_PCB::VIA& aCadstarVia )
2579{
2580 PCB_VIA* via = new PCB_VIA( m_board );
2581 m_board->Add( via, ADD_MODE::APPEND );
2582
2583 VIACODE csViaCode = getViaCode( aCadstarVia.ViaCodeID );
2584 LAYERPAIR csLayerPair = getLayerPair( aCadstarVia.LayerPairID );
2585
2586 via->SetPosition( getKiCadPoint( aCadstarVia.Location ) );
2587 via->SetDrill( getKiCadLength( csViaCode.DrillDiameter ) );
2588 via->SetLocked( aCadstarVia.Fixed );
2589
2590 if( csViaCode.Shape.ShapeType != PAD_SHAPE_TYPE::CIRCLE )
2591 {
2592 reportError( wxString::Format( _( "The CADSTAR via code '%s' has different shape from a "
2593 "circle defined. KiCad only supports circular vias so "
2594 "this via type has been changed to be a via with "
2595 "circular shape of %.2f mm diameter." ), //format:allow
2596 csViaCode.Name,
2597 (double) ( (double) getKiCadLength( csViaCode.Shape.Size ) / 1E6 ) ) );
2598 }
2599
2600 via->SetWidth( PADSTACK::ALL_LAYERS, getKiCadLength( csViaCode.Shape.Size ) );
2601
2602 bool start_layer_outside = csLayerPair.PhysicalLayerStart == 1
2603 || csLayerPair.PhysicalLayerStart == Assignments.Technology.MaxPhysicalLayer;
2604 bool end_layer_outside = csLayerPair.PhysicalLayerEnd == 1
2605 || csLayerPair.PhysicalLayerEnd == Assignments.Technology.MaxPhysicalLayer;
2606
2607 if( start_layer_outside && end_layer_outside )
2608 via->SetViaType( VIATYPE::THROUGH );
2609 else if( ( !start_layer_outside ) && ( !end_layer_outside ) )
2610 via->SetViaType( VIATYPE::BURIED );
2611 else
2612 via->SetViaType( VIATYPE::BLIND );
2613
2614 via->SetLayerPair( getKiCadCopperLayerID( csLayerPair.PhysicalLayerStart ),
2615 getKiCadCopperLayerID( csLayerPair.PhysicalLayerEnd ) );
2616 via->SetNet( getKiCadNet( aCadstarNetID ) );
2617
2618 return via->GetWidth( PADSTACK::ALL_LAYERS );
2619}
2620
2621
2623 BOARD_ITEM_CONTAINER* aContainer,
2624 const GROUP_ID& aCadstarGroupID,
2625 const LAYER_ID& aCadstarLayerOverride,
2626 const VECTOR2I& aMoveVector,
2627 double aRotationAngle, double aScalingFactor,
2628 const VECTOR2I& aTransformCentre,
2629 bool aMirrorInvert )
2630{
2631 PCB_TEXT* txt = new PCB_TEXT( aContainer );
2632 aContainer->Add( txt );
2633 txt->SetText( aCadstarText.Text );
2634
2635 EDA_ANGLE rotationAngle( aRotationAngle, TENTHS_OF_A_DEGREE_T );
2636 VECTOR2I rotatedTextPos = getKiCadPoint( aCadstarText.Position );
2637 RotatePoint( rotatedTextPos, aTransformCentre, rotationAngle );
2638 rotatedTextPos.x = KiROUND( ( rotatedTextPos.x - aTransformCentre.x ) * aScalingFactor );
2639 rotatedTextPos.y = KiROUND( ( rotatedTextPos.y - aTransformCentre.y ) * aScalingFactor );
2640 rotatedTextPos += aTransformCentre;
2641 txt->SetTextPos( rotatedTextPos );
2642 txt->SetPosition( rotatedTextPos );
2643
2644 txt->SetTextAngle( getAngle( aCadstarText.OrientAngle ) + rotationAngle );
2645
2646 txt->SetMirrored( aCadstarText.Mirror );
2647
2648 applyTextCode( txt, aCadstarText.TextCodeID );
2649
2650 switch( aCadstarText.Alignment )
2651 {
2652 case ALIGNMENT::NO_ALIGNMENT: // Default for Single line text is Bottom Left
2656 break;
2657
2661 break;
2662
2666 break;
2667
2671 break;
2672
2676 break;
2677
2681 break;
2682
2683 case ALIGNMENT::TOPLEFT:
2686 break;
2687
2691 break;
2692
2696 break;
2697
2698 default:
2699 wxFAIL_MSG( wxT( "Unknown Alignment - needs review!" ) );
2700 }
2701
2702 if( aMirrorInvert )
2703 txt->Flip( aTransformCentre, FLIP_DIRECTION::LEFT_RIGHT );
2704
2705 //scale it after flipping:
2706 if( aScalingFactor != 1.0 )
2707 {
2708 VECTOR2I unscaledTextSize = txt->GetTextSize();
2709 int unscaledThickness = txt->GetTextThickness();
2710
2711 VECTOR2I scaledTextSize;
2712 scaledTextSize.x = KiROUND( (double) unscaledTextSize.x * aScalingFactor );
2713 scaledTextSize.y = KiROUND( (double) unscaledTextSize.y * aScalingFactor );
2714
2715 txt->SetTextSize( scaledTextSize );
2716 txt->SetTextThickness( KiROUND( (double) unscaledThickness * aScalingFactor ) );
2717 }
2718
2719 txt->Move( aMoveVector );
2720
2721 if( aCadstarText.Alignment == ALIGNMENT::NO_ALIGNMENT )
2723
2724 LAYER_ID layersToDrawOn = aCadstarLayerOverride;
2725
2726 if( layersToDrawOn.IsEmpty() )
2727 layersToDrawOn = aCadstarText.LayerID;
2728
2729 if( isLayerSet( layersToDrawOn ) )
2730 {
2731 //Make a copy on each layer
2732 for( PCB_LAYER_ID layer : getKiCadLayerSet( layersToDrawOn ).Seq() )
2733 {
2734 txt->SetLayer( layer );
2735 PCB_TEXT* newtxt = static_cast<PCB_TEXT*>( txt->Duplicate( IGNORE_PARENT_GROUP ) );
2736 m_board->Add( newtxt, ADD_MODE::APPEND );
2737
2738 if( !aCadstarGroupID.IsEmpty() )
2739 addToGroup( aCadstarGroupID, newtxt );
2740 }
2741
2742 m_board->Remove( txt );
2743 delete txt;
2744 }
2745 else
2746 {
2747 txt->SetLayer( getKiCadLayer( layersToDrawOn ) );
2748
2749 if( !aCadstarGroupID.IsEmpty() )
2750 addToGroup( aCadstarGroupID, txt );
2751 }
2752}
2753
2754
2756 const PCB_LAYER_ID& aKiCadLayer,
2757 int aLineThickness,
2758 const wxString& aShapeName,
2759 BOARD_ITEM_CONTAINER* aContainer,
2760 const GROUP_ID& aCadstarGroupID,
2761 const VECTOR2I& aMoveVector,
2762 double aRotationAngle, double aScalingFactor,
2763 const VECTOR2I& aTransformCentre,
2764 bool aMirrorInvert )
2765{
2766 auto drawAsOutline =
2767 [&]()
2768 {
2769 drawCadstarVerticesAsShapes( aCadstarShape.Vertices, aKiCadLayer, aLineThickness, aContainer,
2770 aCadstarGroupID, aMoveVector, aRotationAngle, aScalingFactor,
2771 aTransformCentre, aMirrorInvert );
2772 drawCadstarCutoutsAsShapes( aCadstarShape.Cutouts, aKiCadLayer, aLineThickness, aContainer,
2773 aCadstarGroupID, aMoveVector, aRotationAngle, aScalingFactor,
2774 aTransformCentre, aMirrorInvert );
2775 };
2776
2777 if( aCadstarShape.Type == SHAPE_TYPE::OPENSHAPE || aCadstarShape.Type == SHAPE_TYPE::OUTLINE )
2778 {
2779 drawAsOutline();
2780 return;
2781 }
2782
2783 // Special case solid shapes that are effectively a single line
2784 if( aCadstarShape.Vertices.size() < 3 )
2785 {
2786 drawAsOutline();
2787 return;
2788 }
2789
2790 PCB_SHAPE* shape = new PCB_SHAPE( aContainer, SHAPE_T::POLY );
2791
2792 if( aCadstarShape.Type == SHAPE_TYPE::SOLID )
2794 else if( getHatchCodeAngle( aCadstarShape.HatchCodeID ) > ANGLE_90 )
2796 else
2797 shape->SetFillMode( FILL_T::HATCH );
2798
2799 SHAPE_POLY_SET shapePolys = getPolySetFromCadstarShape( aCadstarShape, -1, aContainer, aMoveVector,
2800 aRotationAngle, aScalingFactor, aTransformCentre,
2801 aMirrorInvert );
2802
2803 shapePolys.Fracture();
2804
2805 shape->SetPolyShape( shapePolys );
2806 shape->SetStroke( STROKE_PARAMS( aLineThickness, LINE_STYLE::SOLID ) );
2807 shape->SetLayer( aKiCadLayer );
2808 aContainer->Add( shape, ADD_MODE::APPEND );
2809
2810 if( !aCadstarGroupID.IsEmpty() )
2811 addToGroup( aCadstarGroupID, shape );
2812}
2813
2814
2815void CADSTAR_PCB_ARCHIVE_LOADER::drawCadstarCutoutsAsShapes( const std::vector<CUTOUT>& aCutouts,
2816 const PCB_LAYER_ID& aKiCadLayer,
2817 int aLineThickness,
2818 BOARD_ITEM_CONTAINER* aContainer,
2819 const GROUP_ID& aCadstarGroupID,
2820 const VECTOR2I& aMoveVector,
2821 double aRotationAngle,
2822 double aScalingFactor,
2823 const VECTOR2I& aTransformCentre,
2824 bool aMirrorInvert )
2825{
2826 for( const CUTOUT& cutout : aCutouts )
2827 {
2828 drawCadstarVerticesAsShapes( cutout.Vertices, aKiCadLayer, aLineThickness, aContainer,
2829 aCadstarGroupID, aMoveVector, aRotationAngle, aScalingFactor,
2830 aTransformCentre, aMirrorInvert );
2831 }
2832}
2833
2834
2835void CADSTAR_PCB_ARCHIVE_LOADER::drawCadstarVerticesAsShapes( const std::vector<VERTEX>& aCadstarVertices,
2836 const PCB_LAYER_ID& aKiCadLayer,
2837 int aLineThickness,
2838 BOARD_ITEM_CONTAINER* aContainer,
2839 const GROUP_ID& aCadstarGroupID,
2840 const VECTOR2I& aMoveVector,
2841 double aRotationAngle,
2842 double aScalingFactor,
2843 const VECTOR2I& aTransformCentre,
2844 bool aMirrorInvert )
2845{
2846 std::vector<PCB_SHAPE*> shapes = getShapesFromVertices( aCadstarVertices, aContainer, aCadstarGroupID,
2847 aMoveVector, aRotationAngle, aScalingFactor,
2848 aTransformCentre, aMirrorInvert );
2849
2850 for( PCB_SHAPE* shape : shapes )
2851 {
2852 shape->SetStroke( STROKE_PARAMS( aLineThickness, LINE_STYLE::SOLID ) );
2853 shape->SetLayer( aKiCadLayer );
2854 shape->SetParent( aContainer );
2855 aContainer->Add( shape, ADD_MODE::APPEND );
2856 }
2857}
2858
2859
2860std::vector<PCB_SHAPE*>
2861CADSTAR_PCB_ARCHIVE_LOADER::getShapesFromVertices( const std::vector<VERTEX>& aCadstarVertices,
2862 BOARD_ITEM_CONTAINER* aContainer,
2863 const GROUP_ID& aCadstarGroupID,
2864 const VECTOR2I& aMoveVector,
2865 double aRotationAngle, double aScalingFactor,
2866 const VECTOR2I& aTransformCentre,
2867 bool aMirrorInvert )
2868{
2869 std::vector<PCB_SHAPE*> shapes;
2870
2871 if( aCadstarVertices.size() < 2 )
2872 //need at least two points to draw a segment! (unlikely but possible to have only one)
2873 return shapes;
2874
2875 const VERTEX* prev = &aCadstarVertices.at( 0 ); // first one should always be a point vertex
2876 const VERTEX* cur;
2877
2878 for( size_t i = 1; i < aCadstarVertices.size(); i++ )
2879 {
2880 cur = &aCadstarVertices.at( i );
2881 shapes.push_back( getShapeFromVertex( prev->End, *cur, aContainer, aCadstarGroupID, aMoveVector,
2882 aRotationAngle, aScalingFactor, aTransformCentre, aMirrorInvert ) );
2883 prev = cur;
2884 }
2885
2886 return shapes;
2887}
2888
2889
2891 const VERTEX& aCadstarVertex,
2892 BOARD_ITEM_CONTAINER* aContainer,
2893 const GROUP_ID& aCadstarGroupID,
2894 const VECTOR2I& aMoveVector,
2895 double aRotationAngle,
2896 double aScalingFactor,
2897 const VECTOR2I& aTransformCentre,
2898 bool aMirrorInvert )
2899{
2900 PCB_SHAPE* shape = nullptr;
2901 bool cw = false;
2902
2903 VECTOR2I startPoint = getKiCadPoint( aCadstarStartPoint );
2904 VECTOR2I endPoint = getKiCadPoint( aCadstarVertex.End );
2905 VECTOR2I centerPoint;
2906
2907 if( aCadstarVertex.Type == VERTEX_TYPE::ANTICLOCKWISE_SEMICIRCLE
2908 || aCadstarVertex.Type == VERTEX_TYPE::CLOCKWISE_SEMICIRCLE )
2909 {
2910 centerPoint = ( startPoint + endPoint ) / 2;
2911 }
2912 else
2913 {
2914 centerPoint = getKiCadPoint( aCadstarVertex.Center );
2915 }
2916
2917 switch( aCadstarVertex.Type )
2918 {
2919
2921 shape = new PCB_SHAPE( aContainer, SHAPE_T::SEGMENT );
2922
2923 shape->SetStart( startPoint );
2924 shape->SetEnd( endPoint );
2925 break;
2926
2929 cw = true;
2931
2934 {
2935 shape = new PCB_SHAPE( aContainer, SHAPE_T::ARC );
2936
2937 shape->SetCenter( centerPoint );
2938 shape->SetStart( startPoint );
2939
2940 EDA_ANGLE arcStartAngle( startPoint - centerPoint );
2941 EDA_ANGLE arcEndAngle( endPoint - centerPoint );
2942 EDA_ANGLE arcAngle = ( arcEndAngle - arcStartAngle ).Normalize();
2943 //TODO: detect if we are supposed to draw a circle instead (i.e. two SEMICIRCLEs with opposite
2944 // start/end points and same centre point)
2945
2946 if( !cw )
2947 arcAngle.NormalizeNegative(); // anticlockwise arc
2948
2949 shape->SetArcAngleAndEnd( arcAngle, true );
2950
2951 break;
2952 }
2953 }
2954
2955 //Apply transforms
2956 if( aMirrorInvert )
2957 shape->Flip( aTransformCentre, FLIP_DIRECTION::LEFT_RIGHT );
2958
2959 if( aScalingFactor != 1.0 )
2960 {
2961 shape->Move( -1*aTransformCentre );
2962 shape->Scale( aScalingFactor );
2963 shape->Move( aTransformCentre );
2964 }
2965
2966 if( aRotationAngle != 0.0 )
2967 shape->Rotate( aTransformCentre, EDA_ANGLE( aRotationAngle, TENTHS_OF_A_DEGREE_T ) );
2968
2969 if( aMoveVector != VECTOR2I{ 0, 0 } )
2970 shape->Move( aMoveVector );
2971
2972 if( !aCadstarGroupID.IsEmpty() )
2973 addToGroup( aCadstarGroupID, shape );
2974
2975 return shape;
2976}
2977
2978
2979ZONE* CADSTAR_PCB_ARCHIVE_LOADER::getZoneFromCadstarShape( const SHAPE& aCadstarShape, const int& aLineThickness,
2980 BOARD_ITEM_CONTAINER* aParentContainer )
2981{
2982 ZONE* zone = new ZONE( aParentContainer );
2983
2984 if( aCadstarShape.Type == SHAPE_TYPE::HATCHED )
2985 {
2988 }
2989 else
2990 {
2992 }
2993
2994 SHAPE_POLY_SET polygon = getPolySetFromCadstarShape( aCadstarShape, aLineThickness );
2995
2996 zone->AddPolygon( polygon.COutline( 0 ) );
2997
2998 for( int i = 0; i < polygon.HoleCount( 0 ); i++ )
2999 zone->AddPolygon( polygon.CHole( 0, i ) );
3000
3001 return zone;
3002}
3003
3004
3006 int aLineThickness,
3007 BOARD_ITEM_CONTAINER* aContainer,
3008 const VECTOR2I& aMoveVector,
3009 double aRotationAngle,
3010 double aScalingFactor,
3011 const VECTOR2I& aTransformCentre,
3012 bool aMirrorInvert )
3013{
3014 GROUP_ID noGroup = wxEmptyString;
3015
3016 std::vector<PCB_SHAPE*> outlineShapes = getShapesFromVertices( aCadstarShape.Vertices,
3017 aContainer, noGroup, aMoveVector,
3018 aRotationAngle, aScalingFactor,
3019 aTransformCentre, aMirrorInvert );
3020
3021 SHAPE_POLY_SET polySet( getLineChainFromShapes( outlineShapes ) );
3022
3023 //cleanup
3024 for( PCB_SHAPE* shape : outlineShapes )
3025 delete shape;
3026
3027 for( const CUTOUT& cutout : aCadstarShape.Cutouts )
3028 {
3029 std::vector<PCB_SHAPE*> cutoutShapes = getShapesFromVertices( cutout.Vertices, aContainer,
3030 noGroup, aMoveVector,
3031 aRotationAngle, aScalingFactor,
3032 aTransformCentre, aMirrorInvert );
3033
3034 polySet.AddHole( getLineChainFromShapes( cutoutShapes ) );
3035
3036 //cleanup
3037 for( PCB_SHAPE* shape : cutoutShapes )
3038 delete shape;
3039 }
3040
3041 polySet.ClearArcs();
3042
3043 if( aLineThickness > 0 )
3044 polySet.Inflate( aLineThickness / 2, CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_HIGH_DEF );
3045
3046#ifdef DEBUG
3047 for( int i = 0; i < polySet.OutlineCount(); ++i )
3048 {
3049 wxASSERT( polySet.Outline( i ).PointCount() > 2 );
3050
3051 for( int j = 0; j < polySet.HoleCount( i ); ++j )
3052 wxASSERT( polySet.Hole( i, j ).PointCount() > 2 );
3053 }
3054#endif
3055
3056 return polySet;
3057}
3058
3059
3061{
3062 SHAPE_LINE_CHAIN lineChain;
3063
3064 for( PCB_SHAPE* shape : aShapes )
3065 {
3066 switch( shape->GetShape() )
3067 {
3068 case SHAPE_T::ARC:
3069 {
3070 SHAPE_ARC arc( shape->GetCenter(), shape->GetStart(), shape->GetArcAngle() );
3071
3072 if( shape->EndsSwapped() )
3073 arc.Reverse();
3074
3075 lineChain.Append( arc );
3076 break;
3077 }
3078
3079 case SHAPE_T::SEGMENT:
3080 lineChain.Append( shape->GetStartX(), shape->GetStartY() );
3081 lineChain.Append( shape->GetEndX(), shape->GetEndY() );
3082 break;
3083
3084 default:
3085 wxFAIL_MSG( wxT( "Drawsegment type is unexpected. Ignored." ) );
3086 }
3087 }
3088
3089 // Shouldn't have less than 3 points to make a closed shape!
3090 wxASSERT( lineChain.PointCount() > 2 );
3091
3092 // Check if it is closed
3093 if( lineChain.GetPoint( 0 ) != lineChain.GetPoint( lineChain.PointCount() - 1 ) )
3094 lineChain.Append( lineChain.GetPoint( 0 ) );
3095
3096 lineChain.SetClosed( true );
3097
3098 return lineChain;
3099}
3100
3101
3102std::vector<PCB_TRACK*> CADSTAR_PCB_ARCHIVE_LOADER::makeTracksFromShapes( const std::vector<PCB_SHAPE*>& aShapes,
3103 BOARD_ITEM_CONTAINER* aParentContainer,
3104 NETINFO_ITEM* aNet,
3105 PCB_LAYER_ID aLayerOverride,
3106 int aWidthOverride )
3107{
3108 std::vector<PCB_TRACK*> tracks;
3109 PCB_TRACK* prevTrack = nullptr;
3110 PCB_TRACK* track = nullptr;
3111
3112 auto addTrack =
3113 [&]( PCB_TRACK* aTrack )
3114 {
3115 // Ignore zero length tracks in the same way as the CADSTAR postprocessor does
3116 // when generating gerbers. Note that CADSTAR reports these as "Route offset
3117 // errors" when running a DRC within CADSTAR, so we shouldn't be getting this in
3118 // general, however it is used to remove any synthetic points added to
3119 // aDrawSegments by the caller of this function.
3120 if( aTrack->GetLength() != 0 )
3121 {
3122 tracks.push_back( aTrack );
3123 aParentContainer->Add( aTrack, ADD_MODE::APPEND );
3124 }
3125 else
3126 {
3127 delete aTrack;
3128 }
3129 };
3130
3131 for( PCB_SHAPE* shape : aShapes )
3132 {
3133 switch( shape->GetShape() )
3134 {
3135 case SHAPE_T::ARC:
3136 {
3137 SHAPE_ARC arc( shape->GetStart(), shape->GetArcMid(), shape->GetEnd(), 0 );
3138
3139 if( shape->EndsSwapped() )
3140 arc.Reverse();
3141
3142 track = new PCB_ARC( aParentContainer, &arc );
3143 break;
3144 }
3145
3146 case SHAPE_T::SEGMENT:
3147 track = new PCB_TRACK( aParentContainer );
3148 track->SetStart( shape->GetStart() );
3149 track->SetEnd( shape->GetEnd() );
3150 break;
3151
3152 default:
3153 wxFAIL_MSG( wxT( "Drawsegment type is unexpected. Ignored." ) );
3154 continue;
3155 }
3156
3157 if( aWidthOverride == -1 )
3158 track->SetWidth( shape->GetWidth() );
3159 else
3160 track->SetWidth( aWidthOverride );
3161
3162 if( aLayerOverride == PCB_LAYER_ID::UNDEFINED_LAYER )
3163 track->SetLayer( shape->GetLayer() );
3164 else
3165 track->SetLayer( aLayerOverride );
3166
3167 if( aNet != nullptr )
3168 track->SetNet( aNet );
3169 else
3170 track->SetNetCode( -1 );
3171
3172 track->SetLocked( shape->IsLocked() );
3173
3174 // Apply route offsetting, mimmicking the behaviour of the CADSTAR post processor
3175 if( prevTrack != nullptr )
3176 {
3177 int offsetAmount = ( track->GetWidth() / 2 ) - ( prevTrack->GetWidth() / 2 );
3178
3179 if( offsetAmount > 0 )
3180 {
3181 // modify the start of the current track
3182 VECTOR2I newStart = track->GetStart();
3183 applyRouteOffset( &newStart, track->GetEnd(), offsetAmount );
3184 track->SetStart( newStart );
3185 }
3186 else if( offsetAmount < 0 )
3187 {
3188 // amend the end of the previous track
3189 VECTOR2I newEnd = prevTrack->GetEnd();
3190 applyRouteOffset( &newEnd, prevTrack->GetStart(), -offsetAmount );
3191 prevTrack->SetEnd( newEnd );
3192 } // don't do anything if offsetAmount == 0
3193
3194 // Add a synthetic track of the thinnest width between the tracks
3195 // to ensure KiCad features works as expected on the imported design
3196 // (KiCad expects tracks are contiguous segments)
3197 if( track->GetStart() != prevTrack->GetEnd() )
3198 {
3199 int minWidth = std::min( track->GetWidth(), prevTrack->GetWidth() );
3200 PCB_TRACK* synthTrack = new PCB_TRACK( aParentContainer );
3201 synthTrack->SetStart( prevTrack->GetEnd() );
3202 synthTrack->SetEnd( track->GetStart() );
3203 synthTrack->SetWidth( minWidth );
3204 synthTrack->SetLocked( track->IsLocked() );
3205 synthTrack->SetNet( track->GetNet() );
3206 synthTrack->SetLayer( track->GetLayer() );
3207 addTrack( synthTrack );
3208 }
3209 }
3210
3211 if( prevTrack )
3212 addTrack( prevTrack );
3213
3214 prevTrack = track;
3215 }
3216
3217 if( track )
3218 addTrack( track );
3219
3220 return tracks;
3221}
3222
3223
3225 const ATTRIBUTE_ID& aCadstarAttributeID,
3226 FOOTPRINT* aFootprint, const wxString& aAttributeValue )
3227{
3228 PCB_FIELD* field;
3229
3230 if( aCadstarAttributeID == COMPONENT_NAME_ATTRID )
3231 {
3232 field = &aFootprint->Reference(); //text should be set outside this function
3233 }
3234 else if( aCadstarAttributeID == PART_NAME_ATTRID )
3235 {
3236 if( aFootprint->Value().GetText().IsEmpty() )
3237 {
3238 // Use PART_NAME_ATTRID as the value is value field is blank
3239 aFootprint->SetValue( aAttributeValue );
3240 field = &aFootprint->Value();
3241 }
3242 else
3243 {
3244 field = new PCB_FIELD( aFootprint, FIELD_T::USER, aCadstarAttributeID );
3245 aFootprint->Add( field );
3246 field->SetText( aAttributeValue );
3247 }
3248 field->SetVisible( false ); //make invisible to avoid clutter.
3249 }
3250 else if( aCadstarAttributeID != COMPONENT_NAME_2_ATTRID
3251 && getAttributeName( aCadstarAttributeID ) == wxT( "Value" ) )
3252 {
3253 if( !aFootprint->Value().GetText().IsEmpty() )
3254 {
3255 //copy the object
3256 aFootprint->Add( aFootprint->Value().Duplicate( IGNORE_PARENT_GROUP ) );
3257 }
3258
3259 aFootprint->SetValue( aAttributeValue );
3260 field = &aFootprint->Value();
3261 field->SetVisible( false ); //make invisible to avoid clutter.
3262 }
3263 else
3264 {
3265 field = new PCB_FIELD( aFootprint, FIELD_T::USER, aCadstarAttributeID );
3266 aFootprint->Add( field );
3267 field->SetText( aAttributeValue );
3268 field->SetVisible( false ); //make all user attributes invisible to avoid clutter.
3269 }
3270
3271 field->SetPosition( getKiCadPoint( aCadstarAttrLoc.Position ) );
3272 field->SetLayer( getKiCadLayer( aCadstarAttrLoc.LayerID ) );
3273 field->SetMirrored( aCadstarAttrLoc.Mirror );
3274 field->SetTextAngle( getAngle( aCadstarAttrLoc.OrientAngle ) );
3275
3276 if( aCadstarAttrLoc.Mirror ) // If mirroring, invert angle to match CADSTAR
3277 field->SetTextAngle( -field->GetTextAngle() );
3278
3279 applyTextCode( field, aCadstarAttrLoc.TextCodeID );
3280
3281 field->SetKeepUpright( false ); //Keeping it upright seems to result in incorrect orientation
3282
3283 switch( aCadstarAttrLoc.Alignment )
3284 {
3285 case ALIGNMENT::NO_ALIGNMENT: // Default for Single line text is Bottom Left
3291 break;
3292
3296 break;
3297
3301 break;
3302
3306 break;
3307
3311 break;
3312
3316 break;
3317
3318 case ALIGNMENT::TOPLEFT:
3321 break;
3322
3326 break;
3327
3331 break;
3332
3333 default:
3334 wxFAIL_MSG( wxT( "Unknown Alignment - needs review!" ) );
3335 }
3336}
3337
3338
3340 const VECTOR2I& aRefPoint,
3341 const long& aOffsetAmount )
3342{
3343 VECTOR2I v( *aPointToOffset - aRefPoint );
3344 int newLength = v.EuclideanNorm() - aOffsetAmount;
3345
3346 if( newLength > 0 )
3347 {
3348 VECTOR2I offsetted = v.Resize( newLength ) + VECTOR2I( aRefPoint );
3349 aPointToOffset->x = offsetted.x;
3350 aPointToOffset->y = offsetted.y;
3351 }
3352 else
3353 {
3354 *aPointToOffset = aRefPoint; // zero length track. Needs to be removed to mimmick
3355 // cadstar behaviour
3356 }
3357}
3358
3359
3360void CADSTAR_PCB_ARCHIVE_LOADER:: applyTextCode( EDA_TEXT* aKiCadText, const TEXTCODE_ID& aCadstarTextCodeID )
3361{
3362 TEXTCODE tc = getTextCode( aCadstarTextCodeID );
3363
3364 aKiCadText->SetTextThickness( getKiCadLength( tc.LineWidth ) );
3365
3366 if( tc.Font.Modifier1 == FONT_BOLD )
3367 aKiCadText->SetBold( true );
3368
3369 if( tc.Font.Italic )
3370 aKiCadText->SetItalic( true );
3371
3372 VECTOR2I textSize;
3373 textSize.x = getKiCadLength( tc.Width );
3374
3375 // The width is zero for all non-cadstar fonts. Using a width equal to the height seems
3376 // to work well for most fonts.
3377 if( textSize.x == 0 )
3378 textSize.x = getKiCadLength( tc.Height );
3379
3380 textSize.y = KiROUND( TXT_HEIGHT_RATIO * (double) getKiCadLength( tc.Height ) );
3381
3382 if( textSize.x == 0 || textSize.y == 0 )
3383 {
3384 // Make zero sized text not visible
3385
3388 }
3389 else
3390 {
3391 aKiCadText->SetTextSize( textSize );
3392 }
3393
3395 aKiCadText->SetFont( font );
3396}
3397
3398
3400{
3401 wxCHECK( Assignments.Codedefs.LineCodes.find( aCadstarLineCodeID ) != Assignments.Codedefs.LineCodes.end(),
3402 m_board->GetDesignSettings().GetLineThickness( PCB_LAYER_ID::Edge_Cuts ) );
3403
3404 return getKiCadLength( Assignments.Codedefs.LineCodes.at( aCadstarLineCodeID ).Width );
3405}
3406
3407
3409 const COPPERCODE_ID& aCadstaCopperCodeID )
3410{
3411 wxCHECK( Assignments.Codedefs.CopperCodes.find( aCadstaCopperCodeID ) != Assignments.Codedefs.CopperCodes.end(),
3412 COPPERCODE() );
3413
3414 return Assignments.Codedefs.CopperCodes.at( aCadstaCopperCodeID );
3415}
3416
3417
3419{
3420 wxCHECK( Assignments.Codedefs.TextCodes.find( aCadstarTextCodeID ) != Assignments.Codedefs.TextCodes.end(),
3421 TEXTCODE() );
3422
3423 return Assignments.Codedefs.TextCodes.at( aCadstarTextCodeID );
3424}
3425
3426
3428{
3429 wxCHECK( Assignments.Codedefs.PadCodes.find( aCadstarPadCodeID ) != Assignments.Codedefs.PadCodes.end(),
3430 PADCODE() );
3431
3432 return Assignments.Codedefs.PadCodes.at( aCadstarPadCodeID );
3433}
3434
3435
3437{
3438 wxCHECK( Assignments.Codedefs.ViaCodes.find( aCadstarViaCodeID ) != Assignments.Codedefs.ViaCodes.end(),
3439 VIACODE() );
3440
3441 return Assignments.Codedefs.ViaCodes.at( aCadstarViaCodeID );
3442}
3443
3444
3446{
3447 wxCHECK( Assignments.Codedefs.LayerPairs.find( aCadstarLayerPairID ) != Assignments.Codedefs.LayerPairs.end(),
3448 LAYERPAIR() );
3449
3450 return Assignments.Codedefs.LayerPairs.at( aCadstarLayerPairID );
3451}
3452
3453
3455{
3456 wxCHECK( Assignments.Codedefs.AttributeNames.find( aCadstarAttributeID )
3457 != Assignments.Codedefs.AttributeNames.end(),
3458 wxEmptyString );
3459
3460 return Assignments.Codedefs.AttributeNames.at( aCadstarAttributeID ).Name;
3461}
3462
3463
3465 const std::map<ATTRIBUTE_ID, ATTRIBUTE_VALUE>& aCadstarAttrMap )
3466{
3467 wxCHECK( aCadstarAttrMap.find( aCadstarAttributeID ) != aCadstarAttrMap.end(), wxEmptyString );
3468
3469 return aCadstarAttrMap.at( aCadstarAttributeID ).Value;
3470}
3471
3472
3475{
3476 if( Assignments.Layerdefs.Layers.find( aCadstarLayerID ) != Assignments.Layerdefs.Layers.end() )
3477 return Assignments.Layerdefs.Layers.at( aCadstarLayerID ).Type;
3478
3479 return LAYER_TYPE::UNDEFINED;
3480}
3481
3482
3484{
3485 wxCHECK( Parts.PartDefinitions.find( aCadstarPartID ) != Parts.PartDefinitions.end(), PART() );
3486
3487 return Parts.PartDefinitions.at( aCadstarPartID );
3488}
3489
3490
3492 const ROUTECODE_ID& aCadstarRouteCodeID )
3493{
3494 wxCHECK( Assignments.Codedefs.RouteCodes.find( aCadstarRouteCodeID ) != Assignments.Codedefs.RouteCodes.end(),
3495 ROUTECODE() );
3496
3497 return Assignments.Codedefs.RouteCodes.at( aCadstarRouteCodeID );
3498}
3499
3500
3502 const HATCHCODE_ID& aCadstarHatchcodeID )
3503{
3504 wxCHECK( Assignments.Codedefs.HatchCodes.find( aCadstarHatchcodeID ) != Assignments.Codedefs.HatchCodes.end(),
3505 HATCHCODE() );
3506
3507 return Assignments.Codedefs.HatchCodes.at( aCadstarHatchcodeID );
3508}
3509
3510
3512{
3513 checkAndLogHatchCode( aCadstarHatchcodeID );
3514 HATCHCODE hcode = getHatchCode( aCadstarHatchcodeID );
3515
3516 if( hcode.Hatches.size() < 1 )
3517 return m_board->GetDesignSettings().GetDefaultZoneSettings().m_HatchOrientation;
3518 else
3519 return getAngle( hcode.Hatches.at( 0 ).OrientAngle );
3520}
3521
3522
3524{
3525 checkAndLogHatchCode( aCadstarHatchcodeID );
3526 HATCHCODE hcode = getHatchCode( aCadstarHatchcodeID );
3527
3528 if( hcode.Hatches.size() < 1 )
3529 return m_board->GetDesignSettings().GetDefaultZoneSettings().m_HatchThickness;
3530 else
3531 return getKiCadLength( hcode.Hatches.at( 0 ).LineWidth );
3532}
3533
3534
3536{
3537 checkAndLogHatchCode( aCadstarHatchcodeID );
3538 HATCHCODE hcode = getHatchCode( aCadstarHatchcodeID );
3539
3540 if( hcode.Hatches.size() < 1 )
3541 return m_board->GetDesignSettings().GetDefaultZoneSettings().m_HatchGap;
3542 else
3543 return getKiCadLength( hcode.Hatches.at( 0 ).Step );
3544}
3545
3546
3548{
3549 wxCHECK( m_groupMap.find( aCadstarGroupID ) != m_groupMap.end(), nullptr );
3550
3551 return m_groupMap.at( aCadstarGroupID );
3552}
3553
3554
3556{
3557 if( m_hatchcodesTested.find( aCadstarHatchcodeID ) != m_hatchcodesTested.end() )
3558 {
3559 return; //already checked
3560 }
3561 else
3562 {
3563 HATCHCODE hcode = getHatchCode( aCadstarHatchcodeID );
3564
3565 if( hcode.Hatches.size() != 2 )
3566 {
3567 reportWarning( wxString::Format(
3568 _( "The CADSTAR Hatching code '%s' has %d hatches defined. "
3569 "KiCad only supports 2 hatches (crosshatching) 90 degrees apart. "
3570 "The imported hatching is crosshatched." ),
3571 hcode.Name, (int) hcode.Hatches.size() ) );
3572 }
3573 else
3574 {
3575 if( hcode.Hatches.at( 0 ).LineWidth != hcode.Hatches.at( 1 ).LineWidth )
3576 {
3577 reportWarning( wxString::Format(
3578 _( "The CADSTAR Hatching code '%s' has different line widths for each "
3579 "hatch. KiCad only supports one width for the hatching. The imported "
3580 "hatching uses the width defined in the first hatch definition, i.e. "
3581 "%.2f mm." ), //format:allow
3582 hcode.Name,
3583 (double) ( (double) getKiCadLength( hcode.Hatches.at( 0 ).LineWidth ) )
3584 / 1E6 ) );
3585 }
3586
3587 if( hcode.Hatches.at( 0 ).Step != hcode.Hatches.at( 1 ).Step )
3588 {
3589 reportWarning( wxString::Format(
3590 _( "The CADSTAR Hatching code '%s' has different step sizes for each "
3591 "hatch. KiCad only supports one step size for the hatching. The imported "
3592 "hatching uses the step size defined in the first hatching definition, "
3593 "i.e. %.2f mm." ), //format:allow
3594 hcode.Name,
3595 (double) ( (double) getKiCadLength( hcode.Hatches.at( 0 ).Step ) )
3596 / 1E6 ) );
3597 }
3598
3599 if( abs( hcode.Hatches.at( 0 ).OrientAngle - hcode.Hatches.at( 1 ).OrientAngle )
3600 != 90000 )
3601 {
3602 reportWarning( wxString::Format(
3603 _( "The hatches in CADSTAR Hatching code '%s' have an angle "
3604 "difference of %.1f degrees. KiCad only supports hatching 90 " //format:allow
3605 "degrees apart. The imported hatching has two hatches 90 "
3606 "degrees apart, oriented %.1f degrees from horizontal." ), //format:allow
3607 hcode.Name,
3608 getAngle( abs( hcode.Hatches.at( 0 ).OrientAngle
3609 - hcode.Hatches.at( 1 ).OrientAngle ) ).AsDegrees(),
3610 getAngle( hcode.Hatches.at( 0 ).OrientAngle ).AsDegrees() ) );
3611 }
3612 }
3613
3614 m_hatchcodesTested.insert( aCadstarHatchcodeID );
3615 }
3616}
3617
3618
3620 PCB_DIMENSION_BASE* aKiCadDim )
3621{
3622 UNITS dimensionUnits = aCadstarDim.LinearUnits;
3623 LINECODE linecode = Assignments.Codedefs.LineCodes.at( aCadstarDim.Line.LineCodeID );
3624
3625 aKiCadDim->SetLayer( getKiCadLayer( aCadstarDim.LayerID ) );
3626 aKiCadDim->SetPrecision( static_cast<DIM_PRECISION>( aCadstarDim.Precision ) );
3627 aKiCadDim->SetStart( getKiCadPoint( aCadstarDim.ExtensionLineParams.Start ) );
3628 aKiCadDim->SetEnd( getKiCadPoint( aCadstarDim.ExtensionLineParams.End ) );
3629 aKiCadDim->SetExtensionOffset( getKiCadLength( aCadstarDim.ExtensionLineParams.Offset ) );
3630 aKiCadDim->SetLineThickness( getKiCadLength( linecode.Width ) );
3631
3632 applyTextCode( aKiCadDim, aCadstarDim.Text.TextCodeID );
3633
3634 // Find prefix and suffix:
3635 wxString prefix = wxEmptyString;
3636 wxString suffix = wxEmptyString;
3637 int startpos = aCadstarDim.Text.Text.Find( wxT( "<@DISTANCE" ) );
3638
3639 if( startpos != wxNOT_FOUND )
3640 {
3641 prefix = ParseTextFields( aCadstarDim.Text.Text.SubString( 0, startpos - 1 ), &m_context );
3642 wxString remainingStr = aCadstarDim.Text.Text.Mid( startpos );
3643 int endpos = remainingStr.Find( "@>" );
3644 suffix = ParseTextFields( remainingStr.Mid( endpos + 2 ), &m_context );
3645 }
3646
3647 if( suffix.StartsWith( wxT( "mm" ) ) )
3648 {
3650 suffix = suffix.Mid( 2 );
3651 }
3652 else
3653 {
3655 }
3656
3657 aKiCadDim->SetPrefix( prefix );
3658 aKiCadDim->SetSuffix( suffix );
3659
3660 if( aCadstarDim.LinearUnits == UNITS::DESIGN )
3661 {
3662 // For now we will hardcode the units as per the original CADSTAR design.
3663 // TODO: update this when KiCad supports design units
3664 aKiCadDim->SetPrecision( static_cast<DIM_PRECISION>( Assignments.Technology.UnitDisplPrecision ) );
3665 dimensionUnits = Assignments.Technology.Units;
3666 }
3667
3668 switch( dimensionUnits )
3669 {
3670 case UNITS::METER:
3671 case UNITS::CENTIMETER:
3672 case UNITS::MICROMETRE:
3673 reportWarning( wxString::Format( _( "Dimension ID %s uses a type of unit that "
3674 "is not supported in KiCad. Millimeters were "
3675 "applied instead." ),
3676 aCadstarDim.ID ) );
3678 case UNITS::MM:
3679 aKiCadDim->SetUnitsMode( DIM_UNITS_MODE::MM );
3680 break;
3681
3682 case UNITS::INCH:
3683 aKiCadDim->SetUnitsMode( DIM_UNITS_MODE::INCH );
3684 break;
3685
3686 case UNITS::THOU:
3687 aKiCadDim->SetUnitsMode( DIM_UNITS_MODE::MILS );
3688 break;
3689
3690 case UNITS::DESIGN:
3691 wxFAIL_MSG( wxT( "We should have handled design units before coming here!" ) );
3692 break;
3693 }
3694}
3695
3696
3698{
3699 std::map<TEMPLATE_ID, std::set<TEMPLATE_ID>> winningOverlaps;
3700
3701 auto inflateValue =
3702 [&]( ZONE* aZoneA, ZONE* aZoneB )
3703 {
3704 int extra = getKiCadLength( Assignments.Codedefs.SpacingCodes.at( wxT( "C_C" ) ).Spacing )
3705 - m_board->GetDesignSettings().m_MinClearance;
3706
3707 int retval = std::max( aZoneA->GetLocalClearance().value(), aZoneB->GetLocalClearance().value() );
3708
3709 retval += extra;
3710
3711 return retval;
3712 };
3713
3714 // Find the error in fill area when guessing that aHigherZone gets filled before aLowerZone
3715 auto errorArea =
3716 [&]( ZONE* aLowerZone, ZONE* aHigherZone ) -> double
3717 {
3718 SHAPE_POLY_SET intersectShape( *aHigherZone->Outline() );
3719 intersectShape.Inflate( inflateValue( aLowerZone, aHigherZone ),
3721
3722 SHAPE_POLY_SET lowerZoneFill( *aLowerZone->GetFilledPolysList( aLayer ) );
3723 SHAPE_POLY_SET lowerZoneOutline( *aLowerZone->Outline() );
3724
3725 lowerZoneOutline.BooleanSubtract( intersectShape );
3726
3727 lowerZoneFill.BooleanSubtract( lowerZoneOutline );
3728
3729 double leftOverArea = lowerZoneFill.Area();
3730
3731 return leftOverArea;
3732 };
3733
3734 auto intersectionAreaOfZoneOutlines =
3735 [&]( ZONE* aZoneA, ZONE* aZoneB ) -> double
3736 {
3737 SHAPE_POLY_SET outLineA( *aZoneA->Outline() );
3738 outLineA.Inflate( inflateValue( aZoneA, aZoneB ), CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_HIGH_DEF );
3739
3740 SHAPE_POLY_SET outLineB( *aZoneA->Outline() );
3741 outLineB.Inflate( inflateValue( aZoneA, aZoneB ), CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_HIGH_DEF );
3742
3743 outLineA.BooleanIntersection( outLineB );
3744
3745 return outLineA.Area();
3746 };
3747
3748 // Lambda to determine if the zone with template ID 'a' is lower priority than 'b'
3749 auto isLowerPriority =
3750 [&]( const TEMPLATE_ID& a, const TEMPLATE_ID& b ) -> bool
3751 {
3752 return winningOverlaps[b].count( a ) > 0;
3753 };
3754
3755 for( std::map<TEMPLATE_ID, ZONE*>::iterator it1 = m_zonesMap.begin(); it1 != m_zonesMap.end(); ++it1 )
3756 {
3757 TEMPLATE& thisTemplate = Layout.Templates.at( it1->first );
3758 ZONE* thisZone = it1->second;
3759
3760 if( !thisZone->GetLayerSet().Contains( aLayer ) )
3761 continue;
3762
3763 for( std::map<TEMPLATE_ID, ZONE*>::iterator it2 = it1;
3764 it2 != m_zonesMap.end(); ++it2 )
3765 {
3766 TEMPLATE& otherTemplate = Layout.Templates.at( it2->first );
3767 ZONE* otherZone = it2->second;
3768
3769 if( thisTemplate.ID == otherTemplate.ID )
3770 continue;
3771
3772 if( !otherZone->GetLayerSet().Contains( aLayer ) )
3773 {
3774 checkPoint();
3775 continue;
3776 }
3777
3778 if( intersectionAreaOfZoneOutlines( thisZone, otherZone ) == 0 )
3779 {
3780 checkPoint();
3781 continue; // The zones do not interact in any way
3782 }
3783
3784 SHAPE_POLY_SET thisZonePolyFill = *thisZone->GetFilledPolysList( aLayer );
3785 SHAPE_POLY_SET otherZonePolyFill = *otherZone->GetFilledPolysList( aLayer );
3786
3787 if( thisZonePolyFill.Area() > 0.0 && otherZonePolyFill.Area() > 0.0 )
3788 {
3789 // Test if this zone were lower priority than other zone, what is the error?
3790 double areaThis = errorArea( thisZone, otherZone );
3791 // Vice-versa
3792 double areaOther = errorArea( otherZone, thisZone );
3793
3794 if( areaThis > areaOther )
3795 {
3796 // thisTemplate is filled before otherTemplate
3797 winningOverlaps[thisTemplate.ID].insert( otherTemplate.ID );
3798 }
3799 else
3800 {
3801 // thisTemplate is filled AFTER otherTemplate
3802 winningOverlaps[otherTemplate.ID].insert( thisTemplate.ID );
3803 }
3804 }
3805 else if( thisZonePolyFill.Area() > 0.0 )
3806 {
3807 // The other template is not filled, this one wins
3808 winningOverlaps[thisTemplate.ID].insert( otherTemplate.ID );
3809 }
3810 else if( otherZonePolyFill.Area() > 0.0 )
3811 {
3812 // This template is not filled, the other one wins
3813 winningOverlaps[otherTemplate.ID].insert( thisTemplate.ID );
3814 }
3815 else
3816 {
3817 // Neither of the templates is poured - use zone outlines instead (bigger outlines
3818 // get a lower priority)
3819 if( intersectionAreaOfZoneOutlines( thisZone, otherZone ) != 0 )
3820 {
3821 if( thisZone->Outline()->Area() > otherZone->Outline()->Area() )
3822 winningOverlaps[otherTemplate.ID].insert( thisTemplate.ID );
3823 else
3824 winningOverlaps[thisTemplate.ID].insert( otherTemplate.ID );
3825 }
3826 }
3827
3828 checkPoint();
3829 }
3830 }
3831
3832 // Build a set of unique TEMPLATE_IDs of all the zones that intersect with another one
3833 std::set<TEMPLATE_ID> intersectingIDs;
3834
3835 for( const auto& idPair : winningOverlaps )
3836 {
3837 intersectingIDs.insert( idPair.first );
3838 intersectingIDs.insert( idPair.second.begin(), idPair.second.end() );
3839 }
3840
3841 // Now store them in a vector
3842 std::vector<TEMPLATE_ID> sortedIDs;
3843
3844 for( const TEMPLATE_ID& id : intersectingIDs )
3845 {
3846 sortedIDs.push_back( id );
3847 }
3848
3849 // sort by priority
3850 std::sort( sortedIDs.begin(), sortedIDs.end(), isLowerPriority );
3851
3852 TEMPLATE_ID prevID = wxEmptyString;
3853
3854 for( const TEMPLATE_ID& id : sortedIDs )
3855 {
3856 if( prevID.IsEmpty() )
3857 {
3858 prevID = id;
3859 continue;
3860 }
3861
3862 wxASSERT( !isLowerPriority( id, prevID ) );
3863
3864 int newPriority = m_zonesMap.at( prevID )->GetAssignedPriority();
3865
3866 // Only increase priority of the current zone
3867 if( isLowerPriority( prevID, id ) )
3868 newPriority++;
3869
3870 m_zonesMap.at( id )->SetAssignedPriority( newPriority );
3871 prevID = id;
3872 }
3873
3874 // Verify
3875 for( const auto& idPair : winningOverlaps )
3876 {
3877 const TEMPLATE_ID& winningID = idPair.first;
3878
3879 for( const TEMPLATE_ID& losingID : idPair.second )
3880 {
3881 if( m_zonesMap.at( losingID )->GetAssignedPriority() > m_zonesMap.at( winningID )->GetAssignedPriority() )
3882 return false;
3883 }
3884 }
3885
3886 return true;
3887}
3888
3889
3891{
3892 if( m_componentMap.find( aCadstarComponentID ) == m_componentMap.end() )
3893 return nullptr;
3894 else
3895 return m_componentMap.at( aCadstarComponentID );
3896}
3897
3898
3900{
3901 VECTOR2I retval;
3902
3903 retval.x = ( aCadstarPoint.x - m_designCenter.x ) * KiCadUnitMultiplier;
3904 retval.y = -( aCadstarPoint.y - m_designCenter.y ) * KiCadUnitMultiplier;
3905
3906 return retval;
3907}
3908
3909
3911{
3912 if( aCadstarNetID.IsEmpty() )
3913 {
3914 return nullptr;
3915 }
3916 else if( m_netMap.find( aCadstarNetID ) != m_netMap.end() )
3917 {
3918 return m_netMap.at( aCadstarNetID );
3919 }
3920 else
3921 {
3922 wxCHECK( Layout.Nets.find( aCadstarNetID ) != Layout.Nets.end(), nullptr );
3923
3924 NET_PCB csNet = Layout.Nets.at( aCadstarNetID );
3925 wxString newName = csNet.Name;
3926
3927 if( csNet.Name.IsEmpty() )
3928 {
3929 if( csNet.Pins.size() > 0 )
3930 {
3931 // Create default KiCad net naming:
3932
3933 NET_PCB::PIN firstPin = ( *csNet.Pins.begin() ).second;
3934 //we should have already loaded the component with loadComponents() :
3935 FOOTPRINT* m = getFootprintFromCadstarID( firstPin.ComponentID );
3936 newName = wxT( "Net-(" );
3937 newName << m->Reference().GetText();
3938 newName << wxT( "-Pad" ) << wxString::Format( wxT( "%ld" ), firstPin.PadID );
3939 newName << wxT( ")" );
3940 }
3941 else
3942 {
3943 wxFAIL_MSG( wxT( "A net with no pins associated?" ) );
3944 newName = wxT( "csNet-" );
3945 newName << wxString::Format( wxT( "%i" ), csNet.SignalNum );
3946 }
3947 }
3948
3949 if( !m_doneNetClassWarning && !csNet.NetClassID.IsEmpty() && csNet.NetClassID != wxT( "NONE" ) )
3950 {
3951 reportInfo( _( "The CADSTAR design contains nets with a 'Net Class' assigned. KiCad "
3952 "does not have an equivalent to CADSTAR's Net Class so these elements "
3953 "were not imported. Note: KiCad's version of 'Net Class' is closer to "
3954 "CADSTAR's 'Net Route Code' (which has been imported for all nets)." ) );
3955 m_doneNetClassWarning = true;
3956 }
3957
3958 if( !m_doneSpacingClassWarning && !csNet.SpacingClassID.IsEmpty() && csNet.SpacingClassID != wxT( "NONE" ) )
3959 {
3960 reportWarning( _( "The CADSTAR design contains nets with a 'Spacing Class' assigned. "
3961 "KiCad does not have an equivalent to CADSTAR's Spacing Class so "
3962 "these elements were not imported. Please review the design rules as "
3963 "copper pours may be affected by this." ) );
3965 }
3966
3967 std::shared_ptr<NET_SETTINGS>& netSettings = m_board->GetDesignSettings().m_NetSettings;
3968 NETINFO_ITEM* netInfo = new NETINFO_ITEM( m_board, newName, ++m_numNets );
3969 std::shared_ptr<NETCLASS> netclass;
3970
3971 std::tuple<ROUTECODE_ID, NETCLASS_ID, SPACING_CLASS_ID> key = { csNet.RouteCodeID,
3972 csNet.NetClassID,
3973 csNet.SpacingClassID };
3974
3975 if( m_netClassMap.find( key ) != m_netClassMap.end() )
3976 {
3977 netclass = m_netClassMap.at( key );
3978 }
3979 else if( auto rcIt = Assignments.Codedefs.RouteCodes.find( csNet.RouteCodeID );
3980 !csNet.RouteCodeID.IsEmpty() && rcIt != Assignments.Codedefs.RouteCodes.end()
3981 && rcIt->second.OptimalWidth > 0 )
3982 {
3983 wxString netClassName;
3984
3985 ROUTECODE rc = getRouteCode( csNet.RouteCodeID );
3986 netClassName += wxT( "Route code: " ) + rc.Name;
3987
3988 if( !csNet.NetClassID.IsEmpty() )
3989 {
3990 CADSTAR_NETCLASS nc = Assignments.Codedefs.NetClasses.at( csNet.NetClassID );
3991 netClassName += wxT( " | Net class: " ) + nc.Name;
3992 }
3993
3994 if( !csNet.SpacingClassID.IsEmpty() )
3995 {
3996 SPCCLASSNAME sp = Assignments.Codedefs.SpacingClassNames.at( csNet.SpacingClassID );
3997 netClassName += wxT( " | Spacing class: " ) + sp.Name;
3998 }
3999
4000 netclass.reset( new NETCLASS( netClassName ) );
4001 netSettings->SetNetclass( netClassName, netclass );
4002 netclass->SetTrackWidth( getKiCadLength( rc.OptimalWidth ) );
4003 m_netClassMap.insert( { key, netclass } );
4004 }
4005 else
4006 {
4007 // No route code specified, route code not found, or it has no usable width; use the
4008 // default netclass
4009 netclass = netSettings->GetDefaultNetclass();
4010 }
4011
4012 m_board->GetDesignSettings().m_NetSettings->SetNetclassPatternAssignment( newName, netclass->GetName() );
4013
4014 netInfo->SetNetClass( netclass );
4015 m_board->Add( netInfo, ADD_MODE::APPEND );
4016 m_netMap.insert( { aCadstarNetID, netInfo } );
4017 return netInfo;
4018 }
4019}
4020
4021
4022PCB_LAYER_ID CADSTAR_PCB_ARCHIVE_LOADER::getKiCadCopperLayerID( unsigned int aLayerNum, bool aDetectMaxLayer )
4023{
4024 if( aDetectMaxLayer && aLayerNum == (unsigned int) m_numCopperLayers )
4025 return PCB_LAYER_ID::B_Cu;
4026
4027 switch( aLayerNum )
4028 {
4029 case 1: return PCB_LAYER_ID::F_Cu;
4030 case 2: return PCB_LAYER_ID::In1_Cu;
4031 case 3: return PCB_LAYER_ID::In2_Cu;
4032 case 4: return PCB_LAYER_ID::In3_Cu;
4033 case 5: return PCB_LAYER_ID::In4_Cu;
4034 case 6: return PCB_LAYER_ID::In5_Cu;
4035 case 7: return PCB_LAYER_ID::In6_Cu;
4036 case 8: return PCB_LAYER_ID::In7_Cu;
4037 case 9: return PCB_LAYER_ID::In8_Cu;
4038 case 10: return PCB_LAYER_ID::In9_Cu;
4039 case 11: return PCB_LAYER_ID::In10_Cu;
4040 case 12: return PCB_LAYER_ID::In11_Cu;
4041 case 13: return PCB_LAYER_ID::In12_Cu;
4042 case 14: return PCB_LAYER_ID::In13_Cu;
4043 case 15: return PCB_LAYER_ID::In14_Cu;
4044 case 16: return PCB_LAYER_ID::In15_Cu;
4045 case 17: return PCB_LAYER_ID::In16_Cu;
4046 case 18: return PCB_LAYER_ID::In17_Cu;
4047 case 19: return PCB_LAYER_ID::In18_Cu;
4048 case 20: return PCB_LAYER_ID::In19_Cu;
4049 case 21: return PCB_LAYER_ID::In20_Cu;
4050 case 22: return PCB_LAYER_ID::In21_Cu;
4051 case 23: return PCB_LAYER_ID::In22_Cu;
4052 case 24: return PCB_LAYER_ID::In23_Cu;
4053 case 25: return PCB_LAYER_ID::In24_Cu;
4054 case 26: return PCB_LAYER_ID::In25_Cu;
4055 case 27: return PCB_LAYER_ID::In26_Cu;
4056 case 28: return PCB_LAYER_ID::In27_Cu;
4057 case 29: return PCB_LAYER_ID::In28_Cu;
4058 case 30: return PCB_LAYER_ID::In29_Cu;
4059 case 31: return PCB_LAYER_ID::In30_Cu;
4060 case 32: return PCB_LAYER_ID::B_Cu;
4061 }
4062
4064}
4065
4066
4068{
4069 wxCHECK( Assignments.Layerdefs.Layers.find( aCadstarLayerID ) != Assignments.Layerdefs.Layers.end(), false );
4070
4071 LAYER& layer = Assignments.Layerdefs.Layers.at( aCadstarLayerID );
4072
4073 switch( layer.Type )
4074 {
4075 case LAYER_TYPE::ALLDOC:
4078 return true;
4079
4080 default:
4081 return false;
4082 }
4083}
4084
4085
4087{
4088 if( getLayerType( aCadstarLayerID ) == LAYER_TYPE::NOLAYER )
4089 {
4090 //The "no layer" is common for CADSTAR documentation symbols
4091 //map it to undefined layer for later processing
4093 }
4094
4095 wxCHECK( m_layermap.find( aCadstarLayerID ) != m_layermap.end(), PCB_LAYER_ID::UNDEFINED_LAYER );
4096
4097 return m_layermap.at( aCadstarLayerID );
4098}
4099
4100
4102{
4103 LAYER_TYPE layerType = getLayerType( aCadstarLayerID );
4104
4105 switch( layerType )
4106 {
4107 case LAYER_TYPE::ALLDOC:
4108 return LSET( { PCB_LAYER_ID::Dwgs_User,
4113
4116
4125
4126 default:
4127 return LSET( { getKiCadLayer( aCadstarLayerID ) } );
4128 }
4129}
4130
4131
4132void CADSTAR_PCB_ARCHIVE_LOADER::addToGroup( const GROUP_ID& aCadstarGroupID, BOARD_ITEM* aKiCadItem )
4133{
4134 wxCHECK( m_groupMap.find( aCadstarGroupID ) != m_groupMap.end(), );
4135
4136 PCB_GROUP* parentGroup = m_groupMap.at( aCadstarGroupID );
4137 parentGroup->AddItem( aKiCadItem );
4138}
4139
4140
4142{
4143 wxString groupName = aName;
4144 int num = 0;
4145
4146 while( m_groupMap.find( groupName ) != m_groupMap.end() )
4147 groupName = aName + wxT( "_" ) + wxString::Format( wxT( "%i" ), ++num );
4148
4149 PCB_GROUP* docSymGroup = new PCB_GROUP( m_board );
4150 m_board->Add( docSymGroup );
4151 docSymGroup->SetName( groupName );
4152 GROUP_ID groupID( groupName );
4153 m_groupMap.insert( { groupID, docSymGroup } );
4154
4155 return groupID;
4156}
int index
@ ERROR_INSIDE
constexpr int ARC_HIGH_DEF
Definition base_units.h:137
constexpr double PCB_IU_PER_MM
Pcbnew IU is 1 nanometer.
Definition base_units.h:68
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
LAYER_T
The allowed types of layers, same as Specctra DSN spec.
Definition board.h:236
@ LT_POWER
Definition board.h:239
@ LT_JUMPER
Definition board.h:241
@ LT_SIGNAL
Definition board.h:238
@ BS_ITEM_TYPE_COPPER
@ BS_ITEM_TYPE_SILKSCREEN
@ BS_ITEM_TYPE_DIELECTRIC
@ BS_ITEM_TYPE_SOLDERMASK
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
#define COMPONENT_NAME_2_ATTRID
Component Name 2 Attribute ID - typically used for indicating the placement of designators in placeme...
#define COMPONENT_NAME_ATTRID
Component Name Attribute ID - typically used for placement of designators on silk screen.
#define PART_NAME_ATTRID
Loads a cpa file into a KiCad BOARD object.
BASE_SET & reset(size_t pos)
Definition base_set.h:143
virtual bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
virtual void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
Container for design settings for a BOARD object.
std::shared_ptr< NET_SETTINGS > m_NetSettings
BOARD_STACKUP & GetStackupDescriptor()
void SetBoardThickness(int aThickness)
int GetLineThickness(PCB_LAYER_ID aLayer) const
Return the default graphic segment thickness from the layer class for the given layer.
Abstract interface for BOARD_ITEMs capable of storing other items inside.
virtual void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false)=0
Adds an item to the container.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:83
virtual BOARD_ITEM * Duplicate(bool addToParentGroup, BOARD_COMMIT *aCommit=nullptr) const
Create a copy of this BOARD_ITEM.
void SetLocked(bool aLocked) override
Definition board_item.h:386
bool IsLocked() const override
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:343
Manage one layer needed to make a physical board.
void SetThickness(int aThickness, int aDielectricSubLayer=0)
void SetMaterial(const wxString &aName, int aDielectricSubLayer=0)
void SetLossTangent(double aTg, int aDielectricSubLayer=0)
void SetEpsilonR(double aEpsilon, int aDielectricSubLayer=0)
void SetLayerName(const wxString &aName)
Manage layers needed to make a physical board.
void RemoveAll()
Delete all items in list and clear the list.
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
int BuildBoardThicknessFromStackup() const
void BuildDefaultStackupList(const BOARD_DESIGN_SETTINGS *aSettings, int aActiveCopperLayersCount=0)
Create a default stackup, according to the current BOARD_DESIGN_SETTINGS settings.
static const std::map< TEXT_FIELD_NAME, wxString > CADSTAR_TO_KICAD_FIELDS
Map between CADSTAR fields and KiCad text variables.
TEXT_FIELD_NAME
These are special fields in text objects enclosed between the tokens '<@' and '>' such as <@[FIELD_NA...
@ NO_ALIGNMENT
NO_ALIGNMENT has different meaning depending on the object type.
static wxString ParseTextFields(const wxString &aTextString, PARSER_CONTEXT *aParserContext)
Replaces CADSTAR fields for the equivalent in KiCad and stores the field values in aParserContext.
wxString LAYER_ID
ID of a Sheet (if schematic) or board Layer (if PCB)
static void FixTextPositionNoAlignment(EDA_TEXT *aKiCadTextItem)
Correct the position of a text element that had NO_ALIGNMENT in CADSTAR.
@ OPENSHAPE
Unfilled open shape. Cannot have cutouts.
@ SOLID
Filled closed shape (solid fill).
@ HATCHED
Filled closed shape (hatch fill).
static const double TXT_HEIGHT_RATIO
CADSTAR fonts are drawn on a 24x24 integer matrix, where the each axis goes from 0 to 24.
void checkPoint()
Updates m_progressReporter or throws if user canceled.
@ DESIGN
Inherits from design units (assumed Assignments->Technology->Units)
PROGRESS_REPORTER * m_progressReporter
std::map< TEMPLATE_ID, ZONE * > m_zonesMap
Map between Cadstar and KiCad zones.
std::map< std::tuple< ROUTECODE_ID, NETCLASS_ID, SPACING_CLASS_ID >, std::shared_ptr< NETCLASS > > m_netClassMap
Map between Cadstar and KiCad classes.
bool m_doneCopperWarning
Used by loadCoppers() to avoid multiple duplicate warnings.
std::set< PADCODE_ID > m_padcodesTested
Used by getKiCadPad() to avoid multiple duplicate warnings.
int getKiCadLength(long long aCadstarLength)
void initStackupItem(const LAYER &aCadstarLayer, BOARD_STACKUP_ITEM *aKiCadItem, int aDielectricSublayer)
int m_numCopperLayers
Number of layers in the design.
void reportError(const wxString &aMsg) const
Report an import issue the user can act on.
std::vector< LAYER_ID > m_powerPlaneLayers
List of layers that are marked as power plane in CADSTAR.
void drawCadstarText(const TEXT &aCadstarText, BOARD_ITEM_CONTAINER *aContainer, const GROUP_ID &aCadstarGroupID=wxEmptyString, const LAYER_ID &aCadstarLayerOverride=wxEmptyString, const VECTOR2I &aMoveVector={ 0, 0 }, double aRotationAngle=0.0, double aScalingFactor=1.0, const VECTOR2I &aTransformCentre={ 0, 0 }, bool aMirrorInvert=false)
bool isLayerSet(const LAYER_ID &aCadstarLayerID)
LAYERPAIR getLayerPair(const LAYERPAIR_ID &aCadstarLayerPairID)
FOOTPRINT * getFootprintFromCadstarID(const COMPONENT_ID &aCadstarComponentID)
PADCODE getPadCode(const PADCODE_ID &aCadstarPadCodeID)
int loadNetVia(const NET_ID &aCadstarNetID, const NET_PCB::VIA &aCadstarVia)
Load via and return via size.
EDA_ANGLE getAngle(const long long &aCadstarAngle)
std::vector< PCB_SHAPE * > getShapesFromVertices(const std::vector< VERTEX > &aCadstarVertices, BOARD_ITEM_CONTAINER *aContainer=nullptr, const GROUP_ID &aCadstarGroupID=wxEmptyString, const VECTOR2I &aMoveVector={ 0, 0 }, double aRotationAngle=0.0, double aScalingFactor=1.0, const VECTOR2I &aTransformCentre={ 0, 0 }, bool aMirrorInvert=false)
Returns a vector of pointers to PCB_SHAPE objects.
void applyTextCode(EDA_TEXT *aKiCadText, const TEXTCODE_ID &aCadstarTextCodeID)
Apply cadstar textcode parameters to a KiCad text object.
std::map< COMPONENT_ID, FOOTPRINT * > m_componentMap
Map between Cadstar and KiCad components on the board.
SHAPE_LINE_CHAIN getLineChainFromShapes(const std::vector< PCB_SHAPE * > &aShapes)
Returns a SHAPE_LINE_CHAIN object from a series of PCB_SHAPE objects.
std::map< PAD_ID, std::vector< PAD_ID > > ASSOCIATED_COPPER_PADS
Map of pad anchor points (first) to copper pads (second).
void applyDimensionSettings(const DIMENSION &aCadstarDim, PCB_DIMENSION_BASE *aKiCadDim)
ZONE * getZoneFromCadstarShape(const SHAPE &aCadstarShape, const int &aLineThickness, BOARD_ITEM_CONTAINER *aParentContainer)
PCB_LAYER_ID getKiCadCopperLayerID(unsigned int aLayerNum, bool aDetectMaxLayer=true)
void reportInfo(const wxString &aMsg) const
std::vector< PCB_TRACK * > makeTracksFromShapes(const std::vector< PCB_SHAPE * > &aShapes, BOARD_ITEM_CONTAINER *aParentContainer, NETINFO_ITEM *aNet=nullptr, PCB_LAYER_ID aLayerOverride=UNDEFINED_LAYER, int aWidthOverride=-1)
Returns a vector of pointers to TRACK/ARC objects.
VIACODE getViaCode(const VIACODE_ID &aCadstarViaCodeID)
VECTOR2I m_designCenter
Used for calculating the required offset to apply to the Cadstar design so that it fits in KiCad canv...
void Load(BOARD *aBoard, PROJECT *aProject)
Loads a CADSTAR PCB Archive file into the KiCad BOARD object given.
void drawCadstarCutoutsAsShapes(const std::vector< CUTOUT > &aCutouts, const PCB_LAYER_ID &aKiCadLayer, int aLineThickness, BOARD_ITEM_CONTAINER *aContainer, const GROUP_ID &aCadstarGroupID=wxEmptyString, const VECTOR2I &aMoveVector={ 0, 0 }, double aRotationAngle=0.0, double aScalingFactor=1.0, const VECTOR2I &aTransformCentre={ 0, 0 }, bool aMirrorInvert=false)
Uses PCB_SHAPEs to draw the cutouts on m_board object.
void logBoardStackupWarning(const wxString &aCadstarLayerName, const PCB_LAYER_ID &aKiCadLayer)
std::vector< FOOTPRINT * > GetLoadedLibraryFootpints() const
Return a copy of the loaded library footprints (caller owns the objects)
PCB_SHAPE * getShapeFromVertex(const POINT &aCadstarStartPoint, const VERTEX &aCadstarVertex, BOARD_ITEM_CONTAINER *aContainer=nullptr, const GROUP_ID &aCadstarGroupID=wxEmptyString, const VECTOR2I &aMoveVector={ 0, 0 }, double aRotationAngle=0.0, double aScalingFactor=1.0, const VECTOR2I &aTransformCentre={ 0, 0 }, bool aMirrorInvert=false)
Returns a pointer to a PCB_SHAPE object.
void checkAndLogHatchCode(const HATCHCODE_ID &aCadstarHatchcodeID)
bool m_doneSpacingClassWarning
Used by getKiCadNet() to avoid multiple duplicate warnings.
int m_numNets
Number of nets loaded so far.
void loadLibraryPads(const SYMDEF_PCB &aComponent, FOOTPRINT *aFootprint)
PAD * getKiCadPad(const COMPONENT_PAD &aCadstarPad, FOOTPRINT *aParent)
void drawCadstarShape(const SHAPE &aCadstarShape, const PCB_LAYER_ID &aKiCadLayer, int aLineThickness, const wxString &aShapeName, BOARD_ITEM_CONTAINER *aContainer, const GROUP_ID &aCadstarGroupID=wxEmptyString, const VECTOR2I &aMoveVector={ 0, 0 }, double aRotationAngle=0.0, double aScalingFactor=1.0, const VECTOR2I &aTransformCentre={ 0, 0 }, bool aMirrorInvert=false)
NETINFO_ITEM * getKiCadNet(const NET_ID &aCadstarNetID)
Searches m_netMap and returns the NETINFO_ITEM pointer if exists.
void logBoardStackupMessage(const wxString &aCadstarLayerName, const PCB_LAYER_ID &aKiCadLayer)
int getLineThickness(const LINECODE_ID &aCadstarLineCodeID)
std::map< NET_ID, NETINFO_ITEM * > m_netMap
Map between Cadstar and KiCad Nets.
void loadComponentAttributes(const COMPONENT &aComponent, FOOTPRINT *aFootprint)
void loadNetTracks(const NET_ID &aCadstarNetID, const NET_PCB::ROUTE &aCadstarRoute, long aDefaultRouteWidth, long aStartWidth=std::numeric_limits< long >::max(), long aEndWidth=std::numeric_limits< long >::max())
PCB_GROUP * getKiCadGroup(const GROUP_ID &aCadstarGroupID)
bool m_logLayerWarnings
Used in loadBoardStackup()
HATCHCODE getHatchCode(const HATCHCODE_ID &aCadstarHatchcodeID)
void loadLibraryCoppers(const SYMDEF_PCB &aComponent, FOOTPRINT *aFootprint)
LAYER_TYPE getLayerType(const LAYER_ID aCadstarLayerID)
void loadLibraryFigures(const SYMDEF_PCB &aComponent, FOOTPRINT *aFootprint)
TEXTCODE getTextCode(const TEXTCODE_ID &aCadstarTextCodeID)
void reportWarning(const wxString &aMsg) const
wxString getAttributeName(const ATTRIBUTE_ID &aCadstarAttributeID)
wxString getAttributeValue(const ATTRIBUTE_ID &aCadstarAttributeID, const std::map< ATTRIBUTE_ID, ATTRIBUTE_VALUE > &aCadstarAttributeMap)
void applyRouteOffset(VECTOR2I *aPointToOffset, const VECTOR2I &aRefPoint, const long &aOffsetAmount)
CADSTAR's Post Processor does an action called "Route Offset" which is applied when a route is wider ...
VECTOR2I getKiCadPoint(const VECTOR2I &aCadstarPoint)
Scales, offsets and inverts y axis to make the point usable directly in KiCad.
void remapUnsureLayers()
Callback m_layerMappingHandler for layers we aren't sure of.
double getAngleTenthDegree(const long long &aCadstarAngle)
LSET getKiCadLayerSet(const LAYER_ID &aCadstarLayerID)
void addToGroup(const GROUP_ID &aCadstarGroupID, BOARD_ITEM *aKiCadItem)
std::map< SYMDEF_ID, FOOTPRINT * > m_libraryMap
Map between Cadstar and KiCad components in the library.
COPPERCODE getCopperCode(const COPPERCODE_ID &aCadstaCopperCodeID)
SHAPE_POLY_SET getPolySetFromCadstarShape(const SHAPE &aCadstarShape, int aLineThickness=-1, BOARD_ITEM_CONTAINER *aContainer=nullptr, const VECTOR2I &aMoveVector={ 0, 0 }, double aRotationAngle=0.0, double aScalingFactor=1.0, const VECTOR2I &aTransformCentre={ 0, 0 }, bool aMirrorInvert=false)
Returns a SHAPE_POLY_SET object from a Cadstar SHAPE.
EDA_ANGLE getHatchCodeAngle(const HATCHCODE_ID &aCadstarHatchcodeID)
int getKiCadHatchCodeThickness(const HATCHCODE_ID &aCadstarHatchcodeID)
PCB_LAYER_ID getKiCadLayer(const LAYER_ID &aCadstarLayerID)
std::set< HATCHCODE_ID > m_hatchcodesTested
Used by checkAndLogHatchCode() to avoid multiple duplicate warnings.
void loadLibraryAreas(const SYMDEF_PCB &aComponent, FOOTPRINT *aFootprint)
GROUP_ID createUniqueGroupID(const wxString &aName)
Adds a new PCB_GROUP* to m_groupMap.
int getKiCadHatchCodeGap(const HATCHCODE_ID &aCadstarHatchcodeID)
std::vector< std::unique_ptr< FOOTPRINT > > LoadLibrary()
Parse a CADSTAR PCB Archive and load the footprints contained within.
ROUTECODE getRouteCode(const ROUTECODE_ID &aCadstarRouteCodeID)
void drawCadstarVerticesAsShapes(const std::vector< VERTEX > &aCadstarVertices, const PCB_LAYER_ID &aKiCadLayer, int aLineThickness, BOARD_ITEM_CONTAINER *aContainer, const GROUP_ID &aCadstarGroupID=wxEmptyString, const VECTOR2I &aMoveVector={ 0, 0 }, double aRotationAngle=0.0, double aScalingFactor=1.0, const VECTOR2I &aTransformCentre={ 0, 0 }, bool aMirrorInvert=false)
Uses PCB_SHAPE to draw the vertices on m_board object.
void addAttribute(const ATTRIBUTE_LOCATION &aCadstarAttrLoc, const ATTRIBUTE_ID &aCadstarAttributeID, FOOTPRINT *aFootprint, const wxString &aAttributeValue)
Adds a CADSTAR Attribute to a KiCad footprint.
std::map< GROUP_ID, PCB_GROUP * > m_groupMap
Map between Cadstar and KiCad groups.
bool calculateZonePriorities(PCB_LAYER_ID &aLayer)
Tries to make a best guess as to the zone priorities based on the pour status.
std::map< LAYER_ID, PCB_LAYER_ID > m_layermap
Map between Cadstar and KiCad Layers.
PAD *& getPadReference(FOOTPRINT *aFootprint, const PAD_ID aCadstarPadID)
bool m_doneNetClassWarning
Used by getKiCadNet() to avoid multiple duplicate warnings.
double getAngleDegrees(const long long &aCadstarAngle)
PART getPart(const PART_ID &aCadstarPartID)
LAYER_MAPPING_HANDLER m_layerMappingHandler
Callback to get layer mapping.
std::map< SYMDEF_ID, ASSOCIATED_COPPER_PADS > m_librarycopperpads
Associated copper pads (if any) for each component library definition.
long PAD_ID
Pad identifier (pin) in the PCB.
void Parse(bool aLibrary=false)
Parses the file.
int KiCadUnitMultiplier
Use this value to convert units in this CPA file to KiCad units.
@ ALLELEC
Inbuilt layer type (cannot be assigned to user layers)
@ ALLDOC
Inbuilt layer type (cannot be assigned to user layers)
@ NOLAYER
Inbuilt layer type (cannot be assigned to user layers)
@ JUMPERLAYER
Inbuilt layer type (cannot be assigned to user layers)
@ ALLLAYER
Inbuilt layer type (cannot be assigned to user layers)
@ ASSCOMPCOPP
Inbuilt layer type (cannot be assigned to user layers)
@ MAXIMUM
The highest PHYSICAL_LAYER_ID currently defined (i.e.
@ THROUGH_HOLE
All physical layers currently defined.
EDA_ANGLE NormalizeNegative()
Definition eda_angle.h:246
double Sin() const
Definition eda_angle.h:178
EDA_ANGLE Normalize180()
Definition eda_angle.h:268
double Cos() const
Definition eda_angle.h:197
void AddItem(EDA_ITEM *aItem)
Add item to group.
Definition eda_group.cpp:58
void SetName(const wxString &aName)
Definition eda_group.h:48
void SetCenter(const VECTOR2I &aCenter)
SHAPE_POLY_SET & GetPolyShape()
virtual void SetFilled(bool aFlag)
Definition eda_shape.h:152
void SetFillMode(FILL_T aFill)
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:89
virtual void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition eda_text.cpp:532
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:110
virtual void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:576
void SetMirrored(bool isMirrored)
Definition eda_text.cpp:388
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:412
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:381
virtual void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition eda_text.cpp:279
void SetBold(bool aBold)
Set the text to be bold - this will also update the font if needed.
Definition eda_text.cpp:330
void SetKeepUpright(bool aKeepUpright)
Definition eda_text.cpp:420
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:265
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition eda_text.cpp:302
void SetFont(KIFONT::FONT *aFont)
Definition eda_text.cpp:495
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:404
void SetPosition(const VECTOR2I &aPos) override
void SetFPID(const LIB_ID &aFPID)
Definition footprint.h:445
void SetOrientation(const EDA_ANGLE &aNewAngle)
PCB_FIELD & Value()
read/write accessors:
Definition footprint.h:893
std::deque< PAD * > & Pads()
Definition footprint.h:375
void SetReference(const wxString &aReference)
Definition footprint.h:863
void SetValue(const wxString &aValue)
Definition footprint.h:884
PCB_FIELD & Reference()
Definition footprint.h:894
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
void AutoPositionFields()
Position Reference and Value fields at the top and bottom of footprint's bounding box.
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
BOARD_ITEM * Duplicate(bool addToParentGroup, BOARD_COMMIT *aCommit=nullptr) const override
Create a copy of this BOARD_ITEM.
void SetLibDescription(const wxString &aDesc)
Definition footprint.h:462
const wxString & GetReference() const
Definition footprint.h:857
FONT is an abstract base class for both outline and stroke fonts.
Definition font.h:94
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
Definition font.cpp:143
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition lib_id.cpp:65
const UTF8 & GetLibItemName() const
Definition lib_id.h:98
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition lseq.h:47
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllBoardTechMask()
Return a mask holding board technical layers (no CU layer) on both side.
Definition lset.cpp:679
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:604
static const LSET & UserMask()
Definition lset.cpp:686
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition lset.cpp:309
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:595
static const LSET & AllLayersMask()
Definition lset.cpp:637
static LSET UserDefinedLayersMask(int aUserDefinedLayerCount=MAX_USER_DEFINED_LAYERS)
Return a mask with the requested number of user defined layers.
Definition lset.cpp:700
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition lset.cpp:184
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Definition lset.h:63
Handle the data for a net.
Definition netinfo.h:46
void SetNetClass(const std::shared_ptr< NETCLASS > &aNetClass)
std::shared_ptr< NETCLASS > GetDefaultNetclass() const
Gets the default netclass for the project.
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:177
Definition pad.h:61
const wxString & GetNumber() const
Definition pad.h:143
void SetNumber(const wxString &aNumber)
Set the pad number (note that it can be alphanumeric, such as the array reference "AA12").
Definition pad.h:142
Abstract dimension API.
virtual void SetEnd(const VECTOR2I &aPoint)
void SetUnitsFormat(const DIM_UNITS_FORMAT aFormat)
virtual void SetStart(const VECTOR2I &aPoint)
void SetPrefix(const wxString &aPrefix)
void SetExtensionOffset(int aOffset)
void SetSuffix(const wxString &aSuffix)
void SetLineThickness(int aWidth)
void SetPrecision(DIM_PRECISION aPrecision)
void SetOverrideText(const wxString &aValue)
virtual VECTOR2I GetStart() const
The dimension's origin is the first feature point for the dimension.
void SetUnitsMode(DIM_UNITS_MODE aMode)
For better understanding of the points that make a dimension:
void SetExtensionHeight(int aHeight)
void SetHeight(int aHeight)
Set the distance from the feature points to the crossbar line.
A leader is a dimension-like object pointing to a specific point.
An orthogonal dimension is like an aligned dimension, but the extension lines are locked to the X or ...
void SetOrientation(DIR aOrientation)
Set the orientation of the dimension line (so, perpendicular to the feature lines).
A set of BOARD_ITEMs (i.e., without duplicates).
Definition pcb_group.h:51
void SetLocked(bool aLocked) override
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
void SetArcAngleAndEnd(const EDA_ANGLE &aAngle, bool aCheckNegativeAngle=false)
Definition pcb_shape.h:107
void SetShape(SHAPE_T aShape) override
Definition pcb_shape.h:200
void SetEnd(const VECTOR2I &aEnd) override
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
void SetPolyShape(const SHAPE_POLY_SET &aShape) override
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void Move(const VECTOR2I &aMoveVector) override
Move this object.
void SetStart(const VECTOR2I &aStart) override
void Scale(double aScale)
void SetStroke(const STROKE_PARAMS &aStroke) override
void SetTextThickness(int aWidth) override
The TextThickness is that set by the user.
Definition pcb_text.cpp:496
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
Definition pcb_text.cpp:613
EDA_ANGLE GetTextAngle() const override
Definition pcb_text.cpp:544
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true) override
Definition pcb_text.cpp:468
virtual void SetPosition(const VECTOR2I &aPos) override
Definition pcb_text.h:95
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition pcb_text.h:97
int GetTextThickness() const override
Definition pcb_text.cpp:481
void SetTextAngle(const EDA_ANGLE &aAngle) override
Definition pcb_text.cpp:553
VECTOR2I GetTextSize() const override
Definition pcb_text.cpp:454
void SetEnd(const VECTOR2I &aEnd)
Definition pcb_track.h:89
void SetStart(const VECTOR2I &aStart)
Definition pcb_track.h:92
const VECTOR2I & GetStart() const
Definition pcb_track.h:93
const VECTOR2I & GetEnd() const
Definition pcb_track.h:90
virtual void SetWidth(int aWidth)
Definition pcb_track.h:86
virtual int GetWidth() const
Definition pcb_track.h:87
Container for project specific data.
Definition project.h:63
void Reverse()
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
virtual const VECTOR2I GetPoint(int aIndex) const override
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
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.
Represent a set of closed polygons.
void BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
double Area()
Return the area of this poly set.
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int HoleCount(int aOutline) const
Returns the number of holes in a given 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.
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
int OutlineCount() const
Return the number of outlines in the set.
void Move(const VECTOR2I &aVector) override
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
virtual VECTOR2I GetStart() const
Definition shape.h:284
Simple container to manage line stroke parameters.
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition vector2d.h:279
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition vector2d.h:381
Handle a list of polygons defining a copper zone.
Definition zone.h:70
void SetHatchThickness(int aThickness)
Definition zone.h:326
void SetNeedRefill(bool aNeedRefill)
Definition zone.h:310
void SetDoNotAllowPads(bool aEnable)
Definition zone.h:832
std::optional< int > GetLocalClearance() const override
Definition zone.cpp:1012
void SetLocalClearance(std::optional< int > aClearance)
Definition zone.h:183
void AddPolygon(std::vector< VECTOR2I > &aPolygon)
Add a polygon to the zone outline.
Definition zone.cpp:1393
std::shared_ptr< SHAPE_POLY_SET > GetFilledPolysList(PCB_LAYER_ID aLayer) const
Definition zone.h:697
void SetMinThickness(int aMinThickness)
Definition zone.h:316
void SetHatchOrientation(const EDA_ANGLE &aStep)
Definition zone.h:332
void SetThermalReliefSpokeWidth(int aThermalReliefSpokeWidth)
Definition zone.h:251
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition zone.cpp:619
SHAPE_POLY_SET * Outline()
Definition zone.h:418
void SetHatchStyle(ZONE_BORDER_DISPLAY_STYLE aStyle)
Definition zone.h:686
SHAPE_POLY_SET * GetFill(PCB_LAYER_ID aLayer)
Definition zone.h:704
void SetIsRuleArea(bool aEnable)
Definition zone.h:814
void SetDoNotAllowTracks(bool aEnable)
Definition zone.h:831
void SetFilledPolysList(PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPolysList)
Set the list of filled polygons.
Definition zone.h:726
void SetIsFilled(bool isFilled)
Definition zone.h:307
void SetFillMode(ZONE_FILL_MODE aFillMode)
Definition zone.cpp:625
bool HasFilledPolysForLayer(PCB_LAYER_ID aLayer) const
Definition zone.h:688
void SetLayerSet(const LSET &aLayerSet) override
Definition zone.cpp:644
void SetDoNotAllowVias(bool aEnable)
Definition zone.h:830
void SetNet(NETINFO_ITEM *aNetInfo) override
Override that drops aNetInfo when this zone is in copper-thieving fill mode.
Definition zone.cpp:610
void SetThermalReliefGap(int aThermalReliefGap)
Definition zone.h:240
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition zone.h:133
void SetDoNotAllowFootprints(bool aEnable)
Definition zone.h:833
void SetDoNotAllowZoneFills(bool aEnable)
Definition zone.h:829
void SetAssignedPriority(unsigned aPriority)
Definition zone.h:117
void SetPadConnection(ZONE_CONNECTION aPadConnection)
Definition zone.h:313
void SetZoneName(const wxString &aName)
Definition zone.h:161
void SetIslandRemovalMode(ISLAND_REMOVAL_MODE aRemove)
Definition zone.h:836
void SetMinIslandArea(long long int aArea)
Definition zone.h:839
void SetHatchGap(int aStep)
Definition zone.h:329
void TransformArcToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc)
Convert arc to multiple straight segments.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
@ ROUND_ALL_CORNERS
All angles are rounded.
#define _(s)
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:413
@ TENTHS_OF_A_DEGREE_T
Definition eda_angle.h:30
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:415
#define IGNORE_PARENT_GROUP
Definition eda_item.h:53
@ SEGMENT
Definition eda_shape.h:46
@ REVERSE_HATCH
Definition eda_shape.h:65
@ HATCH
Definition eda_shape.h:64
@ FILLED_SHAPE
Fill with object color.
Definition eda_shape.h:61
#define DEFAULT_SIZE_TEXT
This is the "default-of-the-default" hardcoded text size; individual application define their own def...
Definition eda_text.h:79
#define THROW_IO_ERRORF(msg,...)
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ In22_Cu
Definition layer_ids.h:83
@ In11_Cu
Definition layer_ids.h:72
@ In29_Cu
Definition layer_ids.h:90
@ In30_Cu
Definition layer_ids.h:91
@ User_8
Definition layer_ids.h:127
@ F_CrtYd
Definition layer_ids.h:112
@ In17_Cu
Definition layer_ids.h:78
@ B_Adhes
Definition layer_ids.h:99
@ Edge_Cuts
Definition layer_ids.h:108
@ Dwgs_User
Definition layer_ids.h:103
@ F_Paste
Definition layer_ids.h:100
@ In9_Cu
Definition layer_ids.h:70
@ Cmts_User
Definition layer_ids.h:104
@ User_6
Definition layer_ids.h:125
@ User_7
Definition layer_ids.h:126
@ In19_Cu
Definition layer_ids.h:80
@ In7_Cu
Definition layer_ids.h:68
@ In28_Cu
Definition layer_ids.h:89
@ In26_Cu
Definition layer_ids.h:87
@ F_Adhes
Definition layer_ids.h:98
@ B_Mask
Definition layer_ids.h:94
@ B_Cu
Definition layer_ids.h:61
@ User_5
Definition layer_ids.h:124
@ Eco1_User
Definition layer_ids.h:105
@ F_Mask
Definition layer_ids.h:93
@ In21_Cu
Definition layer_ids.h:82
@ In23_Cu
Definition layer_ids.h:84
@ B_Paste
Definition layer_ids.h:101
@ In15_Cu
Definition layer_ids.h:76
@ In2_Cu
Definition layer_ids.h:63
@ User_9
Definition layer_ids.h:128
@ F_Fab
Definition layer_ids.h:115
@ In10_Cu
Definition layer_ids.h:71
@ F_SilkS
Definition layer_ids.h:96
@ In4_Cu
Definition layer_ids.h:65
@ B_CrtYd
Definition layer_ids.h:111
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ Eco2_User
Definition layer_ids.h:106
@ In16_Cu
Definition layer_ids.h:77
@ In24_Cu
Definition layer_ids.h:85
@ In1_Cu
Definition layer_ids.h:62
@ User_3
Definition layer_ids.h:122
@ User_1
Definition layer_ids.h:120
@ B_SilkS
Definition layer_ids.h:97
@ In13_Cu
Definition layer_ids.h:74
@ User_4
Definition layer_ids.h:123
@ In8_Cu
Definition layer_ids.h:69
@ In14_Cu
Definition layer_ids.h:75
@ User_2
Definition layer_ids.h:121
@ In12_Cu
Definition layer_ids.h:73
@ In27_Cu
Definition layer_ids.h:88
@ In6_Cu
Definition layer_ids.h:67
@ In5_Cu
Definition layer_ids.h:66
@ In3_Cu
Definition layer_ids.h:64
@ In20_Cu
Definition layer_ids.h:81
@ F_Cu
Definition layer_ids.h:60
@ In18_Cu
Definition layer_ids.h:79
@ In25_Cu
Definition layer_ids.h:86
@ B_Fab
Definition layer_ids.h:114
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition macros.h:79
@ LEFT_RIGHT
Flip left to right (around the Y axis)
Definition mirror.h:24
constexpr int Mils2IU(const EDA_IU_SCALE &aIuScale, int mils)
Definition eda_units.h:171
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:103
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:99
@ PTH
Plated through hole pad.
Definition padstack.h:98
@ CHAMFERED_RECT
Definition padstack.h:60
@ ROUNDRECT
Definition padstack.h:57
@ RECTANGLE
Definition padstack.h:54
DIM_PRECISION
Class to handle a set of BOARD_ITEMs.
#define KEY_PREPREG
#define KEY_CORE
ALIGNMENT Alignment
In CADSTAR The default alignment for a TEXT object (when "(No Alignment()" is selected) Bottom Left o...
bool HasLocation
Flag to know if this ATTRIBUTE_VALUE has a location i.e.
Represent a cutout in a closed shape (e.g.
long ScaleRatioNumerator
Documentation symbols can be arbitrarily scaled when added to a design.
long ScaleRatioDenominator
Documentation symbols can be arbitrarily scaled when added to a design.
POINT Origin
Origin of the component (this is used as the reference point when placing the component in the design...
LAYER_ID LayerID
Move all objects in the Symdef to this layer.
SYMDEF_ID SymdefID
Normally documentation symbols only have TEXT, FIGURE and TEXT_LOCATION objects which are all drawn o...
GROUP_ID GroupID
If not empty, this FIGURE is part of a group.
long Modifier1
It seems this is related to weight. 400=Normal, 700=Bold.
GROUP_ID GroupID
If not empty, this GROUP is part of another GROUP.
ROUTECODE_ID RouteCodeID
"NETCODE" subnode
wxString Name
This is undefined (wxEmptyString) if the net is unnamed.
NETCLASS_ID NetClassID
The net might not have a net class, in which case it will be wxEmptyString ("NETCLASSREF" subnode)
SPACING_CLASS_ID SpacingClassID
The net might not have a spacing class, in which case it will be wxEmptyString ("SPACINGCLASS" subnod...
long SignalNum
This is undefined if the net has been given a name.
wxString Name
This name can be different to the PART name.
std::map< PART_DEFINITION_PIN_ID, PIN > Pins
Represent a point in x,y coordinates.
wxString HatchCodeID
Only Applicable for HATCHED Type.
std::vector< CUTOUT > Cutouts
Not Applicable to OPENSHAPE Type.
std::map< FIGURE_ID, FIGURE > Figures
POINT Origin
Origin of the component (this is used as the reference point when placing the component in the design...
wxString Alternate
This is in addition to ReferenceName.
wxString ReferenceName
This is the name which identifies the symbol in the library Multiple components may exist with the sa...
long Width
Defaults to 0 if using system fonts or, if using CADSTAR font, default to equal height (1:1 aspect ra...
ALIGNMENT Alignment
In CADSTAR The default alignment for a TEXT object (when "(No Alignment)" is selected) Bottom Left of...
< Nodename = "VARIANT" or "VMASTER" (master variant
Represents a vertex in a shape.
From CADSTAR Help: "Area is for creating areas within which, and nowhere else, certain operations are...
bool Keepout
From CADSTAR Help: "Auto Placement cannot place components within this area.
bool Placement
From CADSTAR Help: "Auto Placement can place components within this area.
bool NoVias
From CADSTAR Help: "No vias will be placed within this area by the automatic router.
bool Routing
From CADSTAR Help: "Area can be used to place routes during Automatic Routing.
bool NoTracks
From CADSTAR Help: "Area cannot be used to place routes during automatic routing.
GROUP_ID GroupID
Normally CADSTAR_BOARD cannot be part of a reuseblock, but included for completeness.
From CADSTAR Help: "Area is for creating areas within which, and nowhere else, certain operations are...
bool NoVias
From CADSTAR Help: "Check this button to specify that any area created by the Rectangle,...
bool NoTracks
From CADSTAR Help: "Check this button to specify that any area created by the Rectangle,...
A shape of copper in the component footprint.
bool PCBonlyPad
From CADSTAR Help: "The PCB Only Pad property can be used to stop ECO Update, Back Annotation,...
POINT Position
Pad position within the component's coordinate frame.
wxString Identifier
This is an identifier that is displayed to the user.
std::map< ATTRIBUTE_ID, ATTRIBUTE_VALUE > AttributeValues
std::map< ATTRIBUTE_ID, TEXT_LOCATION > TextLocations
This contains location of any attributes, including designator position.
TEMPLATE_ID PouredTemplateID
If not empty, it means this COPPER is part of a poured template.
long Overshoot
Overshoot of the extension line past the arrow line.
long LeaderLineExtensionLength
Only for TYPE=LEADERLINE Length of the horizontal part of the leader line [param6].
long LeaderLineLength
Only for TYPE=LEADERLINE Length of the angled part of the leader line [param5].
long LeaderAngle
Only for TYPE=LEADERLINE subnode "LEADERANG".
Linear, leader (radius/diameter) or angular dimension.
LAYER_ID LayerID
ID on which to draw this [param1].
EXTENSION_LINE ExtensionLineParams
Not applicable to TYPE=LEADERDIM.
DIMENSION_ID ID
Some ID (doesn't seem to be used) subnode="DIMREF".
long Precision
Number of decimal points to display in the measurement [param3].
long Thickness
Note: Units of length are defined in file header.
std::map< NETELEMENT_ID, JUNCTION_PCB > Junctions
long ReliefWidth
if undefined inherits from design
std::map< LAYER_ID, CADSTAR_PAD_SHAPE > Reassigns
long ReliefClearance
if undefined inherits from design
PADCODE_ID PadCode
If not empty, override padcode.
std::map< PAD_ID, COMPONENT_PAD > ComponentPads
std::vector< COMPONENT_COPPER > ComponentCoppers
std::map< COMP_AREA_ID, COMPONENT_AREA > ComponentAreas
long AdditionalIsolation
This is the gap to apply in routes and pads in addition to the existing pad-to-copper or route-to-cop...
bool ThermalReliefOnVias
false when subnode "NOVIARELIEF" is present
HATCHCODE_ID HatchCodeID
Only for FillType = HATCHED.
bool ThermalReliefOnPads
false when subnode "NOPINRELIEF" is present
long ThermalReliefPadsAngle
Orientation for the thermal reliefs.
long MinDisjointCopper
The value is the length of one side of a notional square.
bool AutomaticRepour
true when subnode "REGENERATE" is present
bool AllowInNoRouting
true when subnode "IGNORETRN" is present
bool BoxIsolatedPins
true when subnode "BOXPINS" is present
long ClearanceWidth
Specifies the space around pads when pouring (i.e.
COPPERCODE_ID ReliefCopperCodeID
From CADSTAR Help: "Relief Copper Code is forselecting the width of line used to draw thethermal reli...
COPPERCODE_ID CopperCodeID
From CADSTAR Help: "Copper Code is for selecting the width of the line used to draw the outline and f...
long ThermalReliefViasAngle
Disabled when !ThermalReliefOnVias (param6)
long MinIsolatedCopper
The value is the length of one side of a notional square.
long SliverWidth
Minimum width of copper that may be created.
Templates are CADSTAR's equivalent to a "filled zone".
POURING Pouring
Copper pour settings (e.g. relief / hatching /etc.)
Describes an imported layer and how it could be mapped to KiCad Layers.
PCB_LAYER_ID AutoMapLayer
Best guess as to what the equivalent KiCad layer might be.
LSET PermittedLayers
KiCad layers that the imported layer can be mapped onto.
wxString Name
Imported layer name as displayed in original application.
@ USER
The field ID hasn't been set yet; field is invalid.
KIBIS_COMPONENT * comp
KIBIS_PIN * pin
bool cw
int clearance
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
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:225
double DEG2RAD(double deg)
Definition trigo.h:162
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:95
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
@ THERMAL
Use thermal relief for pads.
Definition zones.h:46
@ FULL
pads are covered by copper
Definition zones.h:47