KiCad PCB EDA Suite
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 Roberto Fernandez Bautista <roberto.fer.bau@gmail.com>
5  * Copyright (C) 2020 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 along
18  * with this program. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
27 
28 #include <board_stackup_manager/stackup_predefined_prms.h> // KEY_COPPER, KEY_CORE, KEY_PREPREG
29 #include <class_board.h>
30 #include <class_dimension.h>
31 #include <pcb_shape.h>
32 #include <fp_shape.h>
33 #include <class_module.h>
34 #include <pcb_text.h>
35 #include <class_track.h>
36 #include <class_zone.h>
38 #include <trigo.h>
39 
40 #include <limits> // std::numeric_limits
41 
42 
44 {
45  mBoard = aBoard;
46  Parse();
47 
49 
50  //Note: can't use getKiCadPoint() due wxPoint being int - need long long to make the check
51  long long designSizeXkicad = (long long) designLimit.x * KiCadUnitMultiplier;
52  long long designSizeYkicad = (long long) designLimit.y * KiCadUnitMultiplier;
53 
54  // Max size limited by the positive dimension of wxPoint (which is an int)
55  long long maxDesignSizekicad = std::numeric_limits<int>::max();
56 
57  if( designSizeXkicad > maxDesignSizekicad || designSizeYkicad > maxDesignSizekicad )
58  {
60  _( "The design is too large and cannot be imported into KiCad. \n"
61  "Please reduce the maximum design size in CADSTAR by navigating to: \n"
62  "Design Tab -> Properties -> Design Options -> Maximum Design Size. \n"
63  "Current Design size: %.2f, %.2f millimeters. \n"
64  "Maximum permitted design size: %.2f, %.2f millimeters.\n" ),
65  (double) designSizeXkicad / PCB_IU_PER_MM,
66  (double) designSizeYkicad / PCB_IU_PER_MM,
67  (double) maxDesignSizekicad / PCB_IU_PER_MM,
68  (double) maxDesignSizekicad / PCB_IU_PER_MM ) );
69  }
70 
73  / 2;
74 
76  {
77  wxLogWarning(
78  _( "The selected file indicates that nets might be out of synchronisation "
79  "with the schematic. It is recommended that you carry out an 'Align Nets' "
80  "procedure in CADSTAR and re-import, to avoid inconsistencies between the "
81  "PCB and the schematic. " ) );
82  }
83 
88  loadGroups();
89  loadBoards();
90  loadFigures();
91  loadTexts();
93  loadAreas();
96  loadTemplates();
97  loadCoppers();
98  loadNets();
99 
100 
101  if( Layout.Trunks.size() > 0 )
102  {
103  wxLogWarning(
104  _( "The CADSTAR design contains Trunk routing elements, which have no KiCad "
105  "equivalent. These elements were not loaded." ) );
106  }
107 
108  if( Layout.VariantHierarchy.Variants.size() > 0 )
109  {
110  wxLogWarning(
111  _( "The CADSTAR design contains variants which has no KiCad equivalent. All "
112  "components have been loaded on top of each other. " ) );
113  }
114 
115  if( Layout.ReuseBlocks.size() > 0 )
116  {
117  wxLogWarning(
118  _( "The CADSTAR design contains re-use blocks which has no KiCad equivalent. The "
119  "re-use block information has been discarded during the import." ) );
120  }
121 
122  wxLogMessage(
123  _( "The CADSTAR design has been imported successfully.\n"
124  "Please review the import errors and warnings (if any)." ) );
125 }
126 
127 
128 void CADSTAR_PCB_ARCHIVE_LOADER::logBoardStackupWarning( const wxString& aCadstarLayerName,
129  const PCB_LAYER_ID& aKiCadLayer )
130 {
131  if( mLogLayerWarnings )
132  {
133  wxLogWarning( wxString::Format(
134  _( "The CADSTAR layer '%s' has no KiCad equivalent. All elements on this "
135  "layer have been mapped to KiCad layer '%s' instead." ),
136  aCadstarLayerName, LSET::Name( aKiCadLayer ) ) );
137  }
138 }
139 
140 
141 void CADSTAR_PCB_ARCHIVE_LOADER::logBoardStackupMessage( const wxString& aCadstarLayerName,
142  const PCB_LAYER_ID& aKiCadLayer )
143 {
144  if( mLogLayerWarnings )
145  {
146  wxLogMessage( wxString::Format(
147  _( "The CADSTAR layer '%s' has been assumed to be a technical layer. All "
148  "elements on this layer have been mapped to KiCad layer '%s'." ),
149  aCadstarLayerName, LSET::Name( aKiCadLayer ) ) );
150  }
151 }
152 
153 
155 {
156  std::map<LAYER_ID, LAYER>& cpaLayers = Assignments.Layerdefs.Layers;
157  std::map<MATERIAL_ID, MATERIAL>& cpaMaterials = Assignments.Layerdefs.Materials;
158  std::vector<LAYER_ID>& cpaLayerStack = Assignments.Layerdefs.LayerStack;
159  unsigned numElecAndPowerLayers = 0;
160  BOARD_DESIGN_SETTINGS& designSettings = mBoard->GetDesignSettings();
161  BOARD_STACKUP& stackup = designSettings.GetStackupDescriptor();
162  int noOfKiCadStackupLayers = 0;
163  int lastElectricalLayerIndex = 0;
164  int dielectricSublayer = 0;
165  int numDielectricLayers = 0;
166  bool prevWasDielectric = false;
167  BOARD_STACKUP_ITEM* tempKiCadLayer = nullptr;
168  std::vector<PCB_LAYER_ID> layerIDs;
169 
170  //Remove all layers except required ones
171  stackup.RemoveAll();
172  layerIDs.push_back( PCB_LAYER_ID::F_CrtYd );
173  layerIDs.push_back( PCB_LAYER_ID::B_CrtYd );
174  layerIDs.push_back( PCB_LAYER_ID::Margin );
175  layerIDs.push_back( PCB_LAYER_ID::Edge_Cuts );
176  designSettings.SetEnabledLayers( LSET( &layerIDs[0], layerIDs.size() ) );
177 
178  for( auto it = cpaLayerStack.begin(); it != cpaLayerStack.end(); ++it )
179  {
181  LAYER_T copperType = LAYER_T::LT_UNDEFINED;
183  wxString layerTypeName = wxEmptyString;
184 
185  if( cpaLayers.find( *it ) == cpaLayers.end() )
186  {
187  THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt: The layer "
188  "stack refers to layer ID '%s' which does not exist in the layer "
189  "definitions." ) );
190  }
191 
192  LAYER curLayer = cpaLayers.at( *it );
193 
194  if( prevWasDielectric && ( curLayer.Type != LAYER_TYPE::CONSTRUCTION ) )
195  {
196  stackup.Add( tempKiCadLayer ); //only add dielectric layers here after all are done
197  dielectricSublayer = 0;
198  prevWasDielectric = false;
199  noOfKiCadStackupLayers++;
200  }
201 
202  switch( curLayer.Type )
203  {
204  case LAYER_TYPE::ALLDOC:
205  case LAYER_TYPE::ALLELEC:
208  case LAYER_TYPE::NOLAYER:
209  //Shouldn't be here if CPA file is correctly parsed and not corrupt
211  _( "Unexpected layer '%s' in layer stack." ), curLayer.Name ) );
212 
214  copperType = LAYER_T::LT_JUMPER;
215  kicadLayerID = getKiCadCopperLayerID( ++numElecAndPowerLayers );
217  layerTypeName = KEY_COPPER;
218  break;
219 
220  case LAYER_TYPE::ELEC:
221  copperType = LAYER_T::LT_SIGNAL;
222  kicadLayerID = getKiCadCopperLayerID( ++numElecAndPowerLayers );
224  layerTypeName = KEY_COPPER;
225  break;
226 
227  case LAYER_TYPE::POWER:
228  copperType = LAYER_T::LT_POWER;
229  kicadLayerID = getKiCadCopperLayerID( ++numElecAndPowerLayers );
231  layerTypeName = KEY_COPPER;
232  mPowerPlaneLayers.push_back( curLayer.ID ); //we will need to add a Copper zone
233  break;
234 
236  kicadLayerID = PCB_LAYER_ID::UNDEFINED_LAYER;
238  prevWasDielectric = true;
239  layerTypeName = KEY_PREPREG;
240  //TODO handle KEY_CORE and KEY_PREPREG
241  //will need to look at CADSTAR layer embedding (see LAYER->Embedding) to
242  //check electrical layers above and below to decide if current layer is prepreg
243  // or core
244  break;
245 
246  case LAYER_TYPE::DOC:
247 
248  if( numElecAndPowerLayers > 0 )
249  kicadLayerID = PCB_LAYER_ID::Dwgs_User;
250  else
251  kicadLayerID = PCB_LAYER_ID::Cmts_User;
252 
253  logBoardStackupWarning( curLayer.Name, kicadLayerID );
254  //TODO: allow user to decide which layer this should be mapped onto.
255  break;
256 
257  case LAYER_TYPE::NONELEC:
258  switch( curLayer.SubType )
259  {
261 
262  if( numElecAndPowerLayers > 0 )
263  kicadLayerID = PCB_LAYER_ID::B_Fab;
264  else
265  kicadLayerID = PCB_LAYER_ID::F_Fab;
266 
267  break;
268 
270 
271  if( numElecAndPowerLayers > 0 )
272  kicadLayerID = PCB_LAYER_ID::B_CrtYd;
273  else
274  kicadLayerID = PCB_LAYER_ID::F_CrtYd;
275 
276  break;
277 
279 
280  if( curLayer.Name.Lower().Contains( "glue" )
281  || curLayer.Name.Lower().Contains( "adhesive" ) )
282  {
283  if( numElecAndPowerLayers > 0 )
284  kicadLayerID = PCB_LAYER_ID::B_Adhes;
285  else
286  kicadLayerID = PCB_LAYER_ID::F_Adhes;
287 
288  logBoardStackupMessage( curLayer.Name, kicadLayerID );
289  }
290  else if( curLayer.Name.Lower().Contains( "silk" )
291  || curLayer.Name.Lower().Contains( "legend" ) )
292  {
293  if( numElecAndPowerLayers > 0 )
294  kicadLayerID = PCB_LAYER_ID::B_SilkS;
295  else
296  kicadLayerID = PCB_LAYER_ID::F_SilkS;
297 
298  logBoardStackupMessage( curLayer.Name, kicadLayerID );
299  }
300  else if( curLayer.Name.Lower().Contains( "assembly" )
301  || curLayer.Name.Lower().Contains( "fabrication" ) )
302  {
303  if( numElecAndPowerLayers > 0 )
304  kicadLayerID = PCB_LAYER_ID::B_Fab;
305  else
306  kicadLayerID = PCB_LAYER_ID::F_Fab;
307 
308  logBoardStackupMessage( curLayer.Name, kicadLayerID );
309  }
310  else if( curLayer.Name.Lower().Contains( "resist" )
311  || curLayer.Name.Lower().Contains( "mask" ) )
312  {
313  if( numElecAndPowerLayers > 0 )
314  kicadLayerID = PCB_LAYER_ID::B_Mask;
315  else
316  kicadLayerID = PCB_LAYER_ID::F_Mask;
317 
318  logBoardStackupMessage( curLayer.Name, kicadLayerID );
319  }
320  else if( curLayer.Name.Lower().Contains( "paste" ) )
321  {
322  if( numElecAndPowerLayers > 0 )
323  kicadLayerID = PCB_LAYER_ID::B_Paste;
324  else
325  kicadLayerID = PCB_LAYER_ID::F_Paste;
326 
327  logBoardStackupMessage( curLayer.Name, kicadLayerID );
328  }
329  else
330  {
331  if( numElecAndPowerLayers > 0 )
332  kicadLayerID = PCB_LAYER_ID::Eco2_User;
333  else
334  kicadLayerID = PCB_LAYER_ID::Eco1_User;
335 
336  logBoardStackupWarning( curLayer.Name, kicadLayerID );
337  }
338 
339  break;
340 
343 
344  if( numElecAndPowerLayers > 0 )
345  {
346  kicadLayerID = PCB_LAYER_ID::B_Paste;
347  layerTypeName = _HKI( "Bottom Solder Paste" );
348  }
349  else
350  {
351  kicadLayerID = PCB_LAYER_ID::F_Paste;
352  layerTypeName = _HKI( "Top Solder Paste" );
353  }
354 
355  break;
356 
359 
360  if( numElecAndPowerLayers > 0 )
361  {
362  kicadLayerID = PCB_LAYER_ID::B_SilkS;
363  layerTypeName = _HKI( "Bottom Silk Screen" );
364  }
365  else
366  {
367  kicadLayerID = PCB_LAYER_ID::F_SilkS;
368  layerTypeName = _HKI( "Top Silk Screen" );
369  }
370 
371  break;
372 
375 
376  if( numElecAndPowerLayers > 0 )
377  {
378  kicadLayerID = PCB_LAYER_ID::B_Mask;
379  layerTypeName = _HKI( "Bottom Solder Mask" );
380  }
381  else
382  {
383  kicadLayerID = PCB_LAYER_ID::F_Mask;
384  layerTypeName = _HKI( "Top Solder Mask" );
385  }
386 
387  break;
388 
390  if( numElecAndPowerLayers > 0 )
391  kicadLayerID = PCB_LAYER_ID::Eco2_User;
392  else
393  kicadLayerID = PCB_LAYER_ID::Eco1_User;
394 
395  logBoardStackupWarning( curLayer.Name, kicadLayerID );
396  break;
397 
399  if( numElecAndPowerLayers > 0 )
400  kicadLayerID = PCB_LAYER_ID::Eco2_User;
401  else
402  kicadLayerID = PCB_LAYER_ID::Eco1_User;
403 
404  logBoardStackupWarning( curLayer.Name, kicadLayerID );
405  break;
406 
407  default:
408  wxFAIL_MSG( "Unknown CADSTAR Layer Sub-type" );
409  break;
410  }
411  break;
412 
413  default:
414  wxFAIL_MSG( "Unknown CADSTAR Layer Type" );
415  break;
416  }
417 
418  mLayermap.insert( std::make_pair( curLayer.ID, kicadLayerID ) );
419 
420  if( dielectricSublayer == 0 )
421  tempKiCadLayer = new BOARD_STACKUP_ITEM( kicadLayerType );
422 
423  tempKiCadLayer->SetLayerName( curLayer.Name );
424  tempKiCadLayer->SetBrdLayerId( kicadLayerID );
425 
426  if( prevWasDielectric )
427  {
428  wxASSERT_MSG( kicadLayerID == PCB_LAYER_ID::UNDEFINED_LAYER,
429  wxT( "Error Processing Dielectric Layer. "
430  "Expected to have undefined layer type" ) );
431 
432  if( dielectricSublayer == 0 )
433  tempKiCadLayer->SetDielectricLayerId( ++numDielectricLayers );
434  else
435  tempKiCadLayer->AddDielectricPrms( dielectricSublayer );
436  }
437 
438  if( curLayer.MaterialId != UNDEFINED_MATERIAL_ID )
439  {
440  tempKiCadLayer->SetMaterial(
441  cpaMaterials[curLayer.MaterialId].Name, dielectricSublayer );
442  tempKiCadLayer->SetEpsilonR( cpaMaterials[curLayer.MaterialId].Permittivity.GetDouble(),
443  dielectricSublayer );
444  tempKiCadLayer->SetLossTangent(
445  cpaMaterials[curLayer.MaterialId].LossTangent.GetDouble(), dielectricSublayer );
446  //TODO add Resistivity when KiCad supports it
447  }
448 
449  tempKiCadLayer->SetThickness(
450  curLayer.Thickness * KiCadUnitMultiplier, dielectricSublayer );
451 
452  if( layerTypeName != wxEmptyString )
453  tempKiCadLayer->SetTypeName( layerTypeName );
454 
455  if( !prevWasDielectric )
456  {
457  stackup.Add( tempKiCadLayer ); //only add non-dielectric layers here
458  ++noOfKiCadStackupLayers;
459  layerIDs.push_back( tempKiCadLayer->GetBrdLayerId() );
460  designSettings.SetEnabledLayers( LSET( &layerIDs[0], layerIDs.size() ) );
461  }
462  else
463  ++dielectricSublayer;
464 
465  if( copperType != LAYER_T::LT_UNDEFINED )
466  {
467  wxASSERT( mBoard->SetLayerType( tempKiCadLayer->GetBrdLayerId(),
468  copperType ) ); //move to outside, need to enable layer in board first
469  lastElectricalLayerIndex = noOfKiCadStackupLayers - 1;
470  wxASSERT( mBoard->SetLayerName(
471  tempKiCadLayer->GetBrdLayerId(), tempKiCadLayer->GetLayerName() ) );
472  //TODO set layer names for other CADSTAR layers when KiCad supports custom
473  //layer names on non-copper layers
474  mCopperLayers.insert( std::make_pair( curLayer.PhysicalLayer, curLayer.ID ) );
475  }
476  }
477 
478  //change last copper layer to be B_Cu instead of an inner layer
479  LAYER_ID cadstarlastElecLayer = mCopperLayers.rbegin()->second;
480 
481  PCB_LAYER_ID lastElecBrdId =
482  stackup.GetStackupLayer( lastElectricalLayerIndex )->GetBrdLayerId();
483 
484  layerIDs.erase(
485  std::remove( layerIDs.begin(), layerIDs.end(), lastElecBrdId ), layerIDs.end() );
486 
487  layerIDs.push_back( PCB_LAYER_ID::B_Cu );
488  tempKiCadLayer = stackup.GetStackupLayer( lastElectricalLayerIndex );
489  tempKiCadLayer->SetBrdLayerId( PCB_LAYER_ID::B_Cu );
490 
491  wxASSERT( mBoard->SetLayerName(
492  tempKiCadLayer->GetBrdLayerId(), tempKiCadLayer->GetLayerName() ) );
493 
494  mLayermap.at( cadstarlastElecLayer ) = PCB_LAYER_ID::B_Cu;
495 
496  //make all layers enabled and visible
497  mBoard->SetEnabledLayers( LSET( &layerIDs[0], layerIDs.size() ) );
498  mBoard->SetVisibleLayers( LSET( &layerIDs[0], layerIDs.size() ) );
499 
500  mBoard->SetCopperLayerCount( numElecAndPowerLayers );
501 }
502 
503 
505 {
506  LSET enabledLayers = mBoard->GetEnabledLayers();
507  LSET validRemappingLayers = enabledLayers | LSET::AllBoardTechMask() |
509 
510  std::vector<INPUT_LAYER_DESC> inputLayers;
511  std::map<wxString, LAYER_ID> cadstarLayerNameMap;
512 
513  for( std::pair<LAYER_ID, PCB_LAYER_ID> layerPair : mLayermap )
514  {
515  LAYER* curLayer = &Assignments.Layerdefs.Layers.at( layerPair.first );
516 
517  //Only remap layers that we aren't sure about
518  if( curLayer->Type == LAYER_TYPE::DOC
519  || ( curLayer->Type == LAYER_TYPE::NONELEC
520  && curLayer->SubType == LAYER_SUBTYPE::LAYERSUBTYPE_NONE )
521  || ( curLayer->Type == LAYER_TYPE::NONELEC
522  && curLayer->SubType == LAYER_SUBTYPE::LAYERSUBTYPE_ROUT )
523  || ( curLayer->Type == LAYER_TYPE::NONELEC
525  {
526  INPUT_LAYER_DESC iLdesc;
527  iLdesc.Name = curLayer->Name;
528  iLdesc.PermittedLayers = validRemappingLayers;
529  iLdesc.AutoMapLayer = layerPair.second;
530 
531  inputLayers.push_back( iLdesc );
532  cadstarLayerNameMap.insert( { curLayer->Name, curLayer->ID } );
533  }
534  }
535 
536  if( inputLayers.size() == 0 )
537  return;
538 
539  // Callback:
540  LAYER_MAP reMappedLayers = mLayerMappingHandler( inputLayers );
541 
542  for( std::pair<wxString, PCB_LAYER_ID> layerPair : reMappedLayers )
543  {
544  if( layerPair.second == PCB_LAYER_ID::UNDEFINED_LAYER )
545  {
546  wxFAIL_MSG( "Unexpected Layer ID" );
547  continue;
548  }
549 
550  LAYER_ID cadstarLayerID = cadstarLayerNameMap.at( layerPair.first );
551  mLayermap.at( cadstarLayerID ) = layerPair.second;
552  enabledLayers |= LSET( layerPair.second );
553  }
554 
555  mBoard->SetEnabledLayers( enabledLayers );
556  mBoard->SetVisibleLayers( enabledLayers );
557 }
558 
559 
561 {
562  BOARD_DESIGN_SETTINGS& ds = mBoard->GetDesignSettings();
563  std::map<SPACINGCODE_ID, SPACINGCODE>& spacingCodes = Assignments.Codedefs.SpacingCodes;
564 
565  auto applyRule = [&]( wxString aID, int* aVal ) {
566  if( spacingCodes.find( aID ) == spacingCodes.end() )
567  wxLogWarning( _( "Design rule %s was not found. This was ignored." ) );
568  else
569  *aVal = getKiCadLength( spacingCodes.at( aID ).Spacing );
570  };
571 
572  //Note: for details on the different spacing codes see SPACINGCODE::ID
573 
574  applyRule( "T_T", &ds.m_MinClearance );
575  applyRule( "C_B", &ds.m_CopperEdgeClearance );
576  applyRule( "H_H", &ds.m_HoleToHoleMin );
577 
579 
580  auto applyNetClassRule = [&]( wxString aID, ::NETCLASS* aNetClassPtr,
581  void ( ::NETCLASS::*aFunc )( int ) ) {
582  int value = -1;
583  applyRule( aID, &value );
584 
585  if( value != -1 )
586  ( aNetClassPtr->*aFunc )( value );
587  };
588 
589  applyNetClassRule( "T_T", ds.GetDefault(), &::NETCLASS::SetClearance );
590 
591  wxLogWarning(
592  _( "KiCad design rules are different from CADSTAR ones. Only the compatible "
593  "design rules were imported. It is recommended that you review the design "
594  "rules that have been applied." ) );
595  wxLogWarning(
596  _( "KiCad design rules are different from CADSTAR ones. Only the compatible "
597  "design rules were imported. It is recommended that you review the design "
598  "rules that have been applied." ) );
599 }
600 
601 
603 {
604  for( std::pair<SYMDEF_ID, SYMDEF_PCB> symPair : Library.ComponentDefinitions )
605  {
606  SYMDEF_ID key = symPair.first;
607  SYMDEF_PCB component = symPair.second;
608  wxString moduleName = component.ReferenceName
609  + ( ( component.Alternate.size() > 0 ) ?
610  ( wxT( " (" ) + component.Alternate + wxT( ")" ) ) :
611  wxT( "" ) );
612  MODULE* m = new MODULE( mBoard );
613  m->SetPosition( getKiCadPoint( component.Origin ) );
614 
615  LIB_ID libID;
616  libID.Parse( moduleName, LIB_ID::LIB_ID_TYPE::ID_PCB, true );
617 
618  m->SetFPID( libID );
619  loadLibraryFigures( component, m );
620  loadLibraryCoppers( component, m );
621  loadLibraryAreas( component, m );
622  loadLibraryPads( component, m );
623 
624  mLibraryMap.insert( std::make_pair( key, m ) );
625  }
626 }
627 
628 
630 {
631  for( std::pair<FIGURE_ID, FIGURE> figPair : aComponent.Figures )
632  {
633  FIGURE& fig = figPair.second;
636  wxString::Format( "Component %s:%s -> Figure %s", aComponent.ReferenceName,
637  aComponent.Alternate, fig.ID ),
638  aModule );
639  }
640 }
641 
642 
644 {
645  for( COMPONENT_COPPER compCopper : aComponent.ComponentCoppers )
646  {
647  int lineThickness = getKiCadLength( getCopperCode( compCopper.CopperCodeID ).CopperWidth );
648 
649  drawCadstarShape( compCopper.Shape, getKiCadLayer( compCopper.LayerID ), lineThickness,
650  wxString::Format( "Component %s:%s -> Copper element", aComponent.ReferenceName,
651  aComponent.Alternate ),
652  aModule );
653  }
654 }
655 
656 
658 {
659  for( std::pair<COMP_AREA_ID, COMPONENT_AREA> areaPair : aComponent.ComponentAreas )
660  {
661  COMPONENT_AREA& area = areaPair.second;
662 
663  if( area.NoVias || area.NoTracks )
664  {
666  area.Shape, getLineThickness( area.LineCodeID ), aModule );
667 
668  aModule->Add( zone, ADD_MODE::APPEND );
669 
670  if( isLayerSet( area.LayerID ) )
671  zone->SetLayerSet( getKiCadLayerSet( area.LayerID ) );
672  else
673  zone->SetLayer( getKiCadLayer( area.LayerID ) );
674 
675  zone->SetIsRuleArea( true ); //import all CADSTAR areas as Keepout zones
676  zone->SetDoNotAllowPads( false ); //no CADSTAR equivalent
677  zone->SetZoneName( area.ID );
678 
679  //There is no distinction between tracks and copper pours in CADSTAR Keepout zones
680  zone->SetDoNotAllowTracks( area.NoTracks );
681  zone->SetDoNotAllowCopperPour( area.NoTracks );
682 
683  zone->SetDoNotAllowVias( area.NoVias );
684  }
685  else
686  {
687  wxString libName = aComponent.ReferenceName;
688 
689  if( !aComponent.Alternate.IsEmpty() )
690  libName << wxT( " (" ) << aComponent.Alternate << wxT( ")" );
691 
692  wxLogError(
693  wxString::Format( _( "The CADSTAR area '%s' in library component '%s' does not "
694  "have a KiCad equivalent. The area is neither a via or"
695  "route keepout area. The area was not imported. " ),
696  area.ID, libName ) );
697  }
698  }
699 }
700 
701 
703 {
704  for( std::pair<PAD_ID, PAD> padPair : aComponent.Pads )
705  {
706  D_PAD* pad = getKiCadPad( padPair.second, aModule );
707  aModule->Add( pad,
708  ADD_MODE::INSERT ); // insert so that we get correct behaviour when finding pads
709  // in the module by PAD_ID - see loadNets()
710  }
711 }
712 
713 
714 D_PAD* CADSTAR_PCB_ARCHIVE_LOADER::getKiCadPad( const PAD& aCadstarPad, MODULE* aParent )
715 {
716  PADCODE csPadcode = getPadCode( aCadstarPad.PadCodeID );
717 
718  D_PAD* pad = new D_PAD( aParent );
719 
720  switch( aCadstarPad.Side )
721  {
722  case PAD_SIDE::MAXIMUM: //Bottom side
724  pad->SetLayerSet( LSET( 3, B_Cu, B_Paste, B_Mask ) );
725  break;
726 
727  case PAD_SIDE::MINIMUM: //TOP side
729  pad->SetLayerSet( LSET( 3, F_Cu, F_Paste, F_Mask ) );
730  break;
731 
733 
734  if( csPadcode.Plated )
736  else
738 
739  pad->SetLayerSet( pad->PTHMask() ); // for now we will assume no paste layers
740  //TODO: We need to read the csPad->Reassigns vector to make sure no paste
741  break;
742 
743  default:
744  wxFAIL_MSG( "Unknown Pad type" );
745  }
746 
747  pad->SetName( aCadstarPad.Identifier.IsEmpty() ?
748  wxString::Format( wxT( "%ld" ), aCadstarPad.ID ) :
749  aCadstarPad.Identifier );
750 
751  if( csPadcode.Shape.Size == 0 )
752  // zero sized pads seems to break KiCad so lets make it very small instead
753  csPadcode.Shape.Size = 1;
754 
755  wxPoint padOffset = { 0, 0 }; // offset of the pad origin (before rotating)
756  wxPoint drillOffset = { 0, 0 }; // offset of the drill origin w.r.t. the pad (before rotating)
757 
758  switch( csPadcode.Shape.ShapeType )
759  {
761  //todo fix: use custom shape instead (Donught shape, i.e. a circle with a hole)
763  pad->SetSize( { getKiCadLength( csPadcode.Shape.Size ),
764  getKiCadLength( csPadcode.Shape.Size ) } );
765  break;
766 
769  pad->SetSize( { getKiCadLength( (long long) csPadcode.Shape.Size
770  + (long long) csPadcode.Shape.LeftLength
771  + (long long) csPadcode.Shape.RightLength ),
772  getKiCadLength( csPadcode.Shape.Size ) } );
775  pad->SetRoundRectRadiusRatio( 0.5 );
776  pad->SetChamferRectRatio( 0.0 );
777 
778  padOffset.x = getKiCadLength( ( (long long) csPadcode.Shape.LeftLength / 2 ) -
779  ( (long long) csPadcode.Shape.RightLength / 2 ) );
780  break;
781 
784  pad->SetSize( { getKiCadLength( csPadcode.Shape.Size ),
785  getKiCadLength( csPadcode.Shape.Size ) } );
786  break;
787 
789  {
790  // Cadstar diamond shape is a square rotated 45 degrees
791  // We convert it in KiCad to a square with chamfered edges
792  int sizeOfSquare = (double) getKiCadLength( csPadcode.Shape.Size ) * sqrt(2.0);
794  pad->SetChamferRectRatio( 0.5 );
795  pad->SetSize( { sizeOfSquare, sizeOfSquare } );
796 
797  padOffset.x = getKiCadLength( ( (long long) csPadcode.Shape.LeftLength / 2 ) -
798  ( (long long) csPadcode.Shape.RightLength / 2 ) );
799  }
800  break;
801 
804  pad->SetSize( { getKiCadLength( (long long) csPadcode.Shape.Size
805  + (long long) csPadcode.Shape.LeftLength
806  + (long long) csPadcode.Shape.RightLength ),
807  getKiCadLength( csPadcode.Shape.Size ) } );
808 
809  padOffset.x = getKiCadLength( ( (long long) csPadcode.Shape.LeftLength / 2 ) -
810  ( (long long) csPadcode.Shape.RightLength / 2 ) );
811  break;
812 
816  pad->SetChamferRectRatio( 0.25 );
817  pad->SetSize( { getKiCadLength( csPadcode.Shape.Size ),
818  getKiCadLength( csPadcode.Shape.Size ) } );
819  break;
820 
823  pad->SetSize( { getKiCadLength( (long long) csPadcode.Shape.Size
824  + (long long) csPadcode.Shape.LeftLength
825  + (long long) csPadcode.Shape.RightLength ),
826  getKiCadLength( csPadcode.Shape.Size ) } );
827 
828  padOffset.x = getKiCadLength( ( (long long) csPadcode.Shape.LeftLength / 2 ) -
829  ( (long long) csPadcode.Shape.RightLength / 2 ) );
830  break;
831 
835  pad->SetSize( { getKiCadLength( (long long) csPadcode.Shape.Size
836  + (long long) csPadcode.Shape.LeftLength
837  + (long long) csPadcode.Shape.RightLength ),
838  getKiCadLength( csPadcode.Shape.Size ) } );
839 
840  padOffset.x = getKiCadLength( ( (long long) csPadcode.Shape.LeftLength / 2 ) -
841  ( (long long) csPadcode.Shape.RightLength / 2 ) );
842  break;
843 
844 
847  pad->SetSize( { getKiCadLength( csPadcode.Shape.Size ),
848  getKiCadLength( csPadcode.Shape.Size ) } );
849  break;
850 
851  default:
852  wxFAIL_MSG( "Unknown Pad Shape" );
853  }
854 
855  if( csPadcode.ReliefClearance != UNDEFINED_VALUE )
856  pad->SetThermalGap( getKiCadLength( csPadcode.ReliefClearance ) );
857 
858  if( csPadcode.ReliefWidth != UNDEFINED_VALUE )
859  pad->SetThermalSpokeWidth( getKiCadLength( csPadcode.ReliefWidth ) );
860 
861 
862  if( csPadcode.DrillDiameter != UNDEFINED_VALUE )
863  {
864  if( csPadcode.SlotLength != UNDEFINED_VALUE )
865  {
867  pad->SetDrillSize( { getKiCadLength( (long long) csPadcode.SlotLength +
868  (long long) csPadcode.DrillDiameter ),
869  getKiCadLength( csPadcode.DrillDiameter ) } );
870  }
871  else
872  {
874  pad->SetDrillSize( { getKiCadLength( csPadcode.DrillDiameter ),
875  getKiCadLength( csPadcode.DrillDiameter ) } );
876  }
877 
878  drillOffset.x = -getKiCadLength( csPadcode.DrillXoffset );
879  drillOffset.y = getKiCadLength( csPadcode.DrillYoffset );
880  }
881 
882 
883  if( csPadcode.SlotOrientation != 0 )
884  {
885  LSET lset = pad->GetLayerSet();
886  lset &= LSET::AllCuMask();
887 
888  if( lset.size() > 0 )
889  {
890  SHAPE_POLY_SET padOutline;
891  PCB_LAYER_ID layer = lset.Seq().at( 0 );
892  int maxError = mBoard->GetDesignSettings().m_MaxError;
893 
894  pad->SetPosition( { 0, 0 } );
895  pad->SetPos0( { 0, 0 } );
896  pad->TransformShapeWithClearanceToPolygon( padOutline, layer, 0, maxError,
898 
899  PCB_SHAPE* padShape = new PCB_SHAPE;
901  padShape->SetPolyShape( padOutline );
902  padShape->SetWidth( 0 );
903  padShape->Move( padOffset - drillOffset );
904  padShape->Rotate( wxPoint( 0, 0 ), 1800.0 - getAngleTenthDegree( csPadcode.SlotOrientation ) );
905 
906 
907  SHAPE_POLY_SET editedPadOutline = padShape->GetPolyShape();
908 
909  if( editedPadOutline.Contains( { 0, 0 } ) )
910  {
912  pad->SetSize( wxSize( { 4, 4 } ) );
914  pad->AddPrimitive( padShape );
915  padOffset = { 0, 0 };
916  }
917  else
918  {
919  // The CADSTAR pad has the hole shape outside the pad shape
920  // Lets just put the hole in the center of the pad instead
921  csPadcode.SlotOrientation = 0;
922  drillOffset = { 0, 0 };
923 
924  if( mPadcodesTested.find( csPadcode.ID ) == mPadcodesTested.end() )
925  {
926  wxLogError( wxString::Format(
927  _( "The CADSTAR pad definition '%s' has the hole shape outside the "
928  "pad shape. The hole has been moved to the center of the pad." ),
929  csPadcode.Name ) );
930 
931  mPadcodesTested.insert( csPadcode.ID );
932  }
933  }
934 
935  }
936  else
937  {
938  wxFAIL_MSG( "No copper layers defined in the pad?" );
939  csPadcode.SlotOrientation = 0;
940  pad->SetOffset( drillOffset );
941  }
942  }
943  else
944  {
945  pad->SetOffset( drillOffset );
946  }
947 
948  double padOrientation = getAngleTenthDegree( aCadstarPad.OrientAngle )
949  + getAngleTenthDegree( csPadcode.Shape.OrientAngle );
950 
951  RotatePoint( &padOffset, padOrientation );
952  RotatePoint( &drillOffset, padOrientation );
953  pad->SetPos0( getKiCadPoint( aCadstarPad.Position ) - aParent->GetPosition() - padOffset
954  - drillOffset );
955  pad->SetOrientation( padOrientation + getAngleTenthDegree( csPadcode.SlotOrientation ) );
956 
957  //TODO handle csPadcode.Reassigns when KiCad supports full padstacks
958 
959  return pad;
960 }
961 
962 
964 {
965  for( std::pair<GROUP_ID, GROUP> groupPair : Layout.Groups )
966  {
967  GROUP& csGroup = groupPair.second;
968 
969  PCB_GROUP* kiGroup = new PCB_GROUP( mBoard );
970 
971  mBoard->Add( kiGroup );
972  kiGroup->SetName( csGroup.Name );
973  kiGroup->SetLocked( csGroup.Fixed );
974 
975  mGroupMap.insert( { csGroup.ID, kiGroup } );
976  }
977 
978  //now add any groups to their parent group
979  for( std::pair<GROUP_ID, GROUP> groupPair : Layout.Groups )
980  {
981  GROUP& csGroup = groupPair.second;
982 
983  if( !csGroup.GroupID.IsEmpty() )
984  {
985  if( mGroupMap.find( csGroup.ID ) == mGroupMap.end() )
986  {
988  _( "The file appears to be corrupt. Unable to find group ID %s "
989  "in the group definitions." ),
990  csGroup.ID ) );
991  }
992  else if( mGroupMap.find( csGroup.ID ) == mGroupMap.end() )
993  {
995  _( "The file appears to be corrupt. Unable to find sub group %s "
996  "in the group map (parent group ID=%s, Name=%s)." ),
997  csGroup.GroupID, csGroup.ID, csGroup.Name ) );
998  }
999  else
1000  {
1001  PCB_GROUP* kiCadGroup = mGroupMap.at( csGroup.ID );
1002  PCB_GROUP* parentGroup = mGroupMap.at( csGroup.GroupID );
1003  parentGroup->AddItem( kiCadGroup );
1004  }
1005  }
1006  }
1007 }
1008 
1009 
1011 {
1012  for( std::pair<BOARD_ID, BOARD> boardPair : Layout.Boards )
1013  {
1014  BOARD& board = boardPair.second;
1015  GROUP_ID boardGroup = createUniqueGroupID( wxT( "Board" ) );
1017  getLineThickness( board.LineCodeID ), wxString::Format( "BOARD %s", board.ID ),
1018  mBoard, boardGroup );
1019 
1020  if( !board.GroupID.IsEmpty() )
1021  {
1022  addToGroup( board.GroupID, getKiCadGroup( boardGroup ) );
1023  }
1024 
1025  //TODO process board attributes when KiCad supports them
1026  }
1027 }
1028 
1029 
1031 {
1032  for( std::pair<FIGURE_ID, FIGURE> figPair : Layout.Figures )
1033  {
1034  FIGURE& fig = figPair.second;
1036  getLineThickness( fig.LineCodeID ), wxString::Format( "FIGURE %s", fig.ID ), mBoard,
1037  fig.GroupID );
1038 
1039  //TODO process "swaprule" (doesn't seem to apply to Layout Figures?)
1040  //TODO process re-use block when KiCad Supports it
1041  //TODO process attributes when KiCad Supports attributes in figures
1042  }
1043 }
1044 
1045 
1047 {
1048  for( std::pair<TEXT_ID, TEXT> txtPair : Layout.Texts )
1049  {
1050  TEXT& csTxt = txtPair.second;
1051  drawCadstarText( csTxt, mBoard );
1052  }
1053 }
1054 
1055 
1057 {
1058  for( std::pair<DIMENSION_ID, DIMENSION> dimPair : Layout.Dimensions )
1059  {
1060  DIMENSION& csDim = dimPair.second;
1061 
1062  switch( csDim.Type )
1063  {
1064  case DIMENSION::TYPE::LINEARDIM:
1065  switch( csDim.Subtype )
1066  {
1067  case DIMENSION::SUBTYPE::DIRECT:
1068  case DIMENSION::SUBTYPE::ORTHOGONAL:
1069  {
1070  ::ALIGNED_DIMENSION* dimension = new ::ALIGNED_DIMENSION( mBoard );
1071  TEXTCODE dimText = getTextCode( csDim.Text.TextCodeID );
1072  mBoard->Add( dimension, ADD_MODE::APPEND );
1073 
1074  dimension->SetLayer( getKiCadLayer( csDim.LayerID ) );
1075  dimension->SetPrecision( csDim.Precision );
1076  dimension->SetStart( getKiCadPoint( csDim.Line.Start ) );
1077  dimension->SetEnd( getKiCadPoint( csDim.Line.End ) );
1078  dimension->Text().SetTextThickness( getKiCadLength( dimText.LineWidth ) );
1079  dimension->Text().SetTextSize( wxSize(
1080  getKiCadLength( dimText.Width ), getKiCadLength( dimText.Height ) ) );
1081 
1082  if( csDim.LinearUnits == UNITS::DESIGN )
1083  {
1085  }
1086 
1087  switch( csDim.LinearUnits )
1088  {
1089  case UNITS::METER:
1090  case UNITS::CENTIMETER:
1091  case UNITS::MM:
1092  case UNITS::MICROMETRE:
1093  dimension->SetUnits( EDA_UNITS::MILLIMETRES );
1094  break;
1095 
1096  case UNITS::INCH:
1097  dimension->SetUnits( EDA_UNITS::INCHES );
1098  break;
1099 
1100  case UNITS::THOU:
1101  dimension->SetUnits( EDA_UNITS::MILS );
1102  break;
1103 
1104  case UNITS::DESIGN:
1105  wxFAIL_MSG( "DESIGN units requested - this should not happen." );
1106  break;
1107 
1108  }
1109  }
1110  continue;
1111 
1112  default: //all others
1113  wxLogError( wxString::Format(
1114  _( "Dimension ID %s has no KiCad equivalent. This was not imported" ),
1115  csDim.ID ) );
1116  break;
1117  }
1118  break;
1119 
1120  case DIMENSION::TYPE::ANGLEDIM:
1121  case DIMENSION::TYPE::LEADERDIM:
1122  default:
1123  wxLogError( wxString::Format(
1124  _( "Dimension ID %s has no KiCad equivalent. This was not imported" ),
1125  csDim.ID ) );
1126  break;
1127  }
1128  }
1129 }
1130 
1131 
1133 {
1134  for( std::pair<AREA_ID, AREA> areaPair : Layout.Areas )
1135  {
1136  AREA& area = areaPair.second;
1137 
1138  if( area.NoVias || area.NoTracks || area.Keepout || area.Routing )
1139  {
1141  area.Shape, getLineThickness( area.LineCodeID ), mBoard );
1142 
1143  mBoard->Add( zone, ADD_MODE::APPEND );
1144 
1145  if( isLayerSet( area.LayerID ) )
1146  zone->SetLayerSet( getKiCadLayerSet( area.LayerID ) );
1147  else
1148  zone->SetLayer( getKiCadLayer( area.LayerID ) );
1149 
1150  zone->SetIsRuleArea( true ); //import all CADSTAR areas as Keepout zones
1151  zone->SetDoNotAllowPads( false ); //no CADSTAR equivalent
1152  zone->SetZoneName( area.Name );
1153 
1154  zone->SetDoNotAllowFootprints( area.Keepout );
1155 
1156  zone->SetDoNotAllowTracks( area.NoTracks );
1157  zone->SetDoNotAllowCopperPour( area.NoTracks );
1158 
1159  zone->SetDoNotAllowVias( area.NoVias );
1160 
1161  if( area.Placement )
1162  wxLogWarning( wxString::Format(
1163  _( "The CADSTAR area '%s' is marked as a placement area in CADSTAR. "
1164  "Placement areas are not supported in KiCad. Only the supported "
1165  "elements for the area were imported." ),
1166  area.Name ) );
1167  }
1168  else
1169  {
1170  wxLogError(
1171  wxString::Format( _( "The CADSTAR area '%s' does not have a KiCad equivalent. "
1172  "Pure Placement areas are not supported." ),
1173  area.Name ) );
1174  }
1175 
1176  //todo Process area.AreaHeight when KiCad supports 3D design rules
1177  //TODO process attributes
1178  //TODO process addition to a group
1179  //TODO process "swaprule"
1180  //TODO process re-use block
1181  }
1182 }
1183 
1184 
1186 {
1187  for( std::pair<COMPONENT_ID, COMPONENT> compPair : Layout.Components )
1188  {
1189  COMPONENT& comp = compPair.second;
1190 
1191  auto moduleIter = mLibraryMap.find( comp.SymdefID );
1192 
1193  if( moduleIter == mLibraryMap.end() )
1194  {
1195  THROW_IO_ERROR( wxString::Format( _( "Unable to find component '%s' in the library"
1196  "(Symdef ID: '%s')" ),
1197  comp.Name, comp.SymdefID ) );
1198  }
1199 
1200  // copy constructor to clone the module from the library
1201  MODULE* m = new MODULE( *moduleIter->second );
1202  const_cast<KIID&>( m->m_Uuid ) = KIID();
1203 
1204  mBoard->Add( m, ADD_MODE::APPEND );
1205 
1206  //Override pads with pad exceptions
1207  if( comp.PadExceptions.size() > 0 )
1208  {
1209  SYMDEF_PCB fpLibEntry = Library.ComponentDefinitions.at( comp.SymdefID );
1210 
1211  for( std::pair<PAD_ID, PADEXCEPTION> padPair : comp.PadExceptions )
1212  {
1213  PADEXCEPTION& padEx = padPair.second;
1214  PAD csPad = fpLibEntry.Pads.at( padPair.first );
1215 
1216  if( !padEx.PadCode.IsEmpty() )
1217  csPad.PadCodeID = padEx.PadCode;
1218 
1219  if( padEx.OverrideExits )
1220  csPad.Exits = padEx.Exits;
1221 
1222  if( padEx.OverrideOrientation )
1223  csPad.OrientAngle = padEx.OrientAngle;
1224 
1225  if( padEx.OverrideSide )
1226  csPad.Side = padEx.Side;
1227 
1228  //Find the pad in the module definition
1229  D_PAD* kiPad = m->Pads().at( padEx.ID - (long) 1 );
1230 
1231  if( kiPad )
1232  delete kiPad;
1233 
1234  m->Pads().at( padEx.ID - (long) 1 ) = getKiCadPad( csPad, m );
1235  }
1236  }
1237 
1238  //set to empty string to avoid duplication when loading attributes:
1239  m->SetValue( wxEmptyString );
1240 
1241  m->SetPosition( getKiCadPoint( comp.Origin ) );
1243  m->SetReference( comp.Name );
1244 
1245  if( comp.Mirror )
1246  {
1247  double mirroredAngle = - getAngleTenthDegree( comp.OrientAngle );
1248  NORMALIZE_ANGLE_180( mirroredAngle );
1249  m->SetOrientation( mirroredAngle );
1250  m->Flip( getKiCadPoint( comp.Origin ), true );
1251  }
1252 
1253  loadComponentAttributes( comp, m );
1254 
1255  if( !comp.PartID.IsEmpty() && comp.PartID != wxT( "NO_PART" ) )
1257 
1258  mComponentMap.insert( { comp.ID, m } );
1259  }
1260 }
1261 
1262 
1264 {
1265  //No KiCad equivalent. Loaded as graphic and text elements instead
1266 
1267  for( std::pair<DOCUMENTATION_SYMBOL_ID, DOCUMENTATION_SYMBOL> docPair :
1269  {
1270  DOCUMENTATION_SYMBOL& docSymInstance = docPair.second;
1271 
1272 
1273  auto docSymIter = Library.ComponentDefinitions.find( docSymInstance.SymdefID );
1274 
1275  if( docSymIter == Library.ComponentDefinitions.end() )
1276  {
1277  THROW_IO_ERROR( wxString::Format( _( "Unable to find documentation symbol in the "
1278  "library (Symdef ID: '%s')" ),
1279  docSymInstance.SymdefID ) );
1280  }
1281 
1282  SYMDEF_PCB& docSymDefinition = ( *docSymIter ).second;
1283  wxPoint moveVector =
1284  getKiCadPoint( docSymInstance.Origin ) - getKiCadPoint( docSymDefinition.Origin );
1285  double rotationAngle = getAngleTenthDegree( docSymInstance.OrientAngle );
1286  double scalingFactor = (double) docSymInstance.ScaleRatioNumerator
1287  / (double) docSymInstance.ScaleRatioDenominator;
1288  wxPoint centreOfTransform = getKiCadPoint( docSymDefinition.Origin );
1289  bool mirrorInvert = docSymInstance.Mirror;
1290 
1291  //create a group to store the items in
1292  wxString groupName = docSymDefinition.ReferenceName;
1293 
1294  if( !docSymDefinition.Alternate.IsEmpty() )
1295  groupName += wxT( " (" ) + docSymDefinition.Alternate + wxT( ")" );
1296 
1297  GROUP_ID groupID = createUniqueGroupID( groupName );
1298 
1299  LSEQ layers = getKiCadLayerSet( docSymInstance.LayerID ).Seq();
1300 
1301  for( PCB_LAYER_ID layer : layers )
1302  {
1303  for( std::pair<FIGURE_ID, FIGURE> figPair : docSymDefinition.Figures )
1304  {
1305  FIGURE fig = figPair.second;
1306  drawCadstarShape( fig.Shape, layer, getLineThickness( fig.LineCodeID ),
1307  wxString::Format( "DOCUMENTATION SYMBOL %s, FIGURE %s",
1308  docSymDefinition.ReferenceName, fig.ID ),
1309  mBoard, groupID, moveVector, rotationAngle, scalingFactor,
1310  centreOfTransform, mirrorInvert );
1311  }
1312  }
1313 
1314  for( std::pair<TEXT_ID, TEXT> textPair : docSymDefinition.Texts )
1315  {
1316  TEXT txt = textPair.second;
1317  drawCadstarText( txt, mBoard, groupID, docSymInstance.LayerID, moveVector,
1318  rotationAngle, scalingFactor, centreOfTransform, mirrorInvert );
1319  }
1320  }
1321 }
1322 
1323 
1325 {
1326  for( std::pair<TEMPLATE_ID, TEMPLATE> tempPair : Layout.Templates )
1327  {
1328  TEMPLATE& csTemplate = tempPair.second;
1329 
1331  csTemplate.Shape, getLineThickness( csTemplate.LineCodeID ), mBoard );
1332 
1333  mBoard->Add( zone, ADD_MODE::APPEND );
1334 
1335  zone->SetZoneName( csTemplate.Name );
1336  zone->SetLayer( getKiCadLayer( csTemplate.LayerID ) );
1337 
1338  if( !( csTemplate.NetID.IsEmpty() || csTemplate.NetID == wxT( "NONE" ) ) )
1339  zone->SetNet( getKiCadNet( csTemplate.NetID ) );
1340 
1341  if( csTemplate.Pouring.AllowInNoRouting )
1342  wxLogError( wxString::Format(
1343  _( "The CADSTAR template '%s' has the setting 'Allow in No Routing Areas' "
1344  "enabled. This setting has no KiCad equivalent, so it has been ignored." ),
1345  csTemplate.Name ) );
1346 
1347  if( csTemplate.Pouring.BoxIsolatedPins )
1348  wxLogError( wxString::Format(
1349  _( "The CADSTAR template '%s' has the setting 'Box Isolated Pins'"
1350  "enabled. This setting has no KiCad equivalent, so it has been ignored." ),
1351  csTemplate.Name ) );
1352 
1353  if( csTemplate.Pouring.AutomaticRepour )
1354  wxLogWarning( wxString::Format(
1355  _( "The CADSTAR template '%s' has the setting 'Automatic Repour'"
1356  "enabled. This setting has no KiCad equivalent, so it has been ignored." ),
1357  csTemplate.Name ) );
1358 
1359  // Sliver width has different behaviour to KiCad Zone's minimum thickness
1360  // In Cadstar 'Sliver width' has to be greater than the Copper thickness, whereas in
1361  // Kicad it is the opposite.
1362  if( csTemplate.Pouring.SliverWidth != 0 )
1363  wxLogError( wxString::Format(
1364  _( "The CADSTAR template '%s' has a non-zero value defined for the "
1365  "'Sliver Width' setting. There is no KiCad equivalent for "
1366  "this, so this setting was ignored." ),
1367  csTemplate.Name ) );
1368 
1369 
1370  if( csTemplate.Pouring.MinIsolatedCopper != csTemplate.Pouring.MinDisjointCopper )
1371  wxLogError( wxString::Format(
1372  _( "The CADSTAR template '%s' has different settings for 'Retain Poured Copper "
1373  "- Disjoint' and 'Retain Poured Copper - Isolated'. KiCad does not "
1374  "distinguish between these two settings. The setting for disjoint copper "
1375  "has been applied as the minimum island area of the KiCad Zone." ),
1376  csTemplate.Name ) );
1377 
1378  if( csTemplate.Pouring.MinDisjointCopper < 0 )
1379  zone->SetMinIslandArea( -1 );
1380  else
1381  zone->SetMinIslandArea(
1382  (long long) getKiCadLength( csTemplate.Pouring.MinDisjointCopper )
1383  * (long long) getKiCadLength( csTemplate.Pouring.MinDisjointCopper ) );
1384 
1386 
1387  if( csTemplate.Pouring.FillType == TEMPLATE::POURING::COPPER_FILL_TYPE::HATCHED )
1388  {
1390  zone->SetHatchGap( getKiCadHatchCodeGap( csTemplate.Pouring.HatchCodeID ) );
1393  }
1394  else
1395  {
1397  }
1398 
1399  if( csTemplate.Pouring.ThermalReliefOnPads != csTemplate.Pouring.ThermalReliefOnVias
1400  || csTemplate.Pouring.ThermalReliefPadsAngle
1401  != csTemplate.Pouring.ThermalReliefViasAngle )
1402  wxLogWarning( wxString::Format(
1403  _( "The CADSTAR template '%s' has different settings for thermal relief "
1404  "in pads and vias. KiCad only supports one single setting for both. The "
1405  "setting for pads has been applied." ),
1406  csTemplate.Name ) );
1407 
1408  if( csTemplate.Pouring.ThermalReliefOnPads )
1409  {
1414  }
1415  else
1417  }
1418 
1419  //Now create power plane layers:
1420  for( LAYER_ID layer : mPowerPlaneLayers )
1421  {
1422  wxASSERT(
1423  Assignments.Layerdefs.Layers.find( layer ) != Assignments.Layerdefs.Layers.end() );
1424 
1425  //The net name will equal the layer name
1426  wxString powerPlaneLayerName = Assignments.Layerdefs.Layers.at( layer ).Name;
1427  NET_ID netid = wxEmptyString;
1428 
1429  for( std::pair<NET_ID, NET_PCB> netPair : Layout.Nets )
1430  {
1431  NET_PCB net = netPair.second;
1432 
1433  if( net.Name == powerPlaneLayerName )
1434  {
1435  netid = net.ID;
1436  break;
1437  }
1438  }
1439 
1440  if( netid.IsEmpty() )
1441  {
1442  wxLogError( wxString::Format(
1443  _( "The CADSTAR layer '%s' is defined as a power plane layer. However no "
1444  "net with such name exists. The layer has been loaded but no copper zone "
1445  "was created." ),
1446  powerPlaneLayerName ) );
1447  }
1448  else
1449  {
1450  for( std::pair<BOARD_ID, BOARD> boardPair : Layout.Boards )
1451  {
1452  //create a zone in each board shape
1453  BOARD& board = boardPair.second;
1454  int defaultLineThicknesss =
1455  mBoard->GetDesignSettings().GetLineThickness( PCB_LAYER_ID::Edge_Cuts );
1456  ZONE_CONTAINER* zone =
1457  getZoneFromCadstarShape( board.Shape, defaultLineThicknesss, mBoard );
1458 
1459  mBoard->Add( zone, ADD_MODE::APPEND );
1460 
1461  zone->SetZoneName( powerPlaneLayerName );
1462  zone->SetLayer( getKiCadLayer( layer ) );
1465  zone->SetMinIslandArea( -1 );
1466  zone->SetNet( getKiCadNet( netid ) );
1467  }
1468  }
1469  }
1470 }
1471 
1472 
1474 {
1475  for( std::pair<COPPER_ID, COPPER> copPair : Layout.Coppers )
1476  {
1477  COPPER& csCopper = copPair.second;
1478 
1479  if( !csCopper.PouredTemplateID.IsEmpty() )
1480  continue; //ignore copper related to a template as we've already loaded it!
1481 
1482  // For now we are going to load coppers to a KiCad zone however this isn't perfect
1483  //TODO: Load onto a graphical polygon with a net (when KiCad has this feature)
1484 
1485  if( !mDoneCopperWarning )
1486  {
1487  wxLogWarning(
1488  _( "The CADSTAR design contains COPPER elements, which have no direct KiCad "
1489  "equivalent. These have been imported as a KiCad Zone if solid or hatch "
1490  "filled, or as a KiCad Track if the shape was an unfilled outline (open or "
1491  "closed)." ) );
1492  mDoneCopperWarning = true;
1493  }
1494 
1495 
1496  if( csCopper.Shape.Type == SHAPE_TYPE::OPENSHAPE
1497  || csCopper.Shape.Type == SHAPE_TYPE::OUTLINE )
1498  {
1499  std::vector<PCB_SHAPE*> outlineSegments =
1501 
1502  std::vector<TRACK*> outlineTracks = makeTracksFromDrawsegments( outlineSegments, mBoard,
1503  getKiCadNet( csCopper.NetRef.NetID ), getKiCadLayer( csCopper.LayerID ),
1505 
1506  //cleanup
1507  for( PCB_SHAPE* seg : outlineSegments )
1508  delete seg;
1509 
1510  for( CUTOUT cutout : csCopper.Shape.Cutouts )
1511  {
1512  std::vector<PCB_SHAPE*> cutoutSeg =
1514 
1515  std::vector<TRACK*> cutoutTracks = makeTracksFromDrawsegments( cutoutSeg, mBoard,
1516  getKiCadNet( csCopper.NetRef.NetID ), getKiCadLayer( csCopper.LayerID ),
1518 
1519  //cleanup
1520  for( PCB_SHAPE* seg : cutoutSeg )
1521  delete seg;
1522  }
1523  }
1524  else
1525  {
1526  ZONE_CONTAINER* zone = getZoneFromCadstarShape( csCopper.Shape,
1528 
1529  mBoard->Add( zone, ADD_MODE::APPEND );
1530 
1531  zone->SetZoneName( csCopper.ID );
1532  zone->SetLayer( getKiCadLayer( csCopper.LayerID ) );
1533 
1534  if( csCopper.Shape.Type == SHAPE_TYPE::HATCHED )
1535  {
1537  zone->SetHatchGap( getKiCadHatchCodeGap( csCopper.Shape.HatchCodeID ) );
1540  }
1541  else
1542  {
1544  }
1545 
1547  zone->SetNet( getKiCadNet( csCopper.NetRef.NetID ) );
1548  }
1549  }
1550 }
1551 
1552 
1554 {
1555  for( std::pair<NET_ID, NET_PCB> netPair : Layout.Nets )
1556  {
1557  NET_PCB net = netPair.second;
1558  wxString netnameForErrorReporting = net.Name;
1559 
1560  if( netnameForErrorReporting.IsEmpty() )
1561  netnameForErrorReporting = wxString::Format( "$%ld", net.SignalNum );
1562 
1563  for( NET_PCB::CONNECTION_PCB connection : net.Connections )
1564  {
1565  if( !connection.Unrouted )
1566  loadNetTracks( net.ID, connection.Route );
1567 
1568  //TODO: all other elements
1569  }
1570 
1571  for( std::pair<NETELEMENT_ID, NET_PCB::VIA> viaPair : net.Vias )
1572  {
1573  NET_PCB::VIA via = viaPair.second;
1574  loadNetVia( net.ID, via );
1575  }
1576 
1577  for( std::pair<NETELEMENT_ID, NET_PCB::PIN> pinPair : net.Pins )
1578  {
1579  NET_PCB::PIN pin = pinPair.second;
1580  MODULE* m = getModuleFromCadstarID( pin.ComponentID );
1581 
1582  if( m == nullptr )
1583  {
1584  wxLogWarning( wxString::Format(
1585  _( "The net '%s' references component ID '%s' which does not exist. "
1586  "This has been ignored," ),
1587  netnameForErrorReporting, pin.ComponentID ) );
1588  }
1589  else if( ( pin.PadID - (long) 1 ) > m->Pads().size() )
1590  {
1591  wxLogWarning( wxString::Format(
1592  _( "The net '%s' references non-existent pad index '%d' in component '%s'. "
1593  "This has been ignored." ),
1594  netnameForErrorReporting, pin.PadID, m->GetReference() ) );
1595  }
1596  else
1597  {
1598  // The below works because we have added the pads in the correct order to the module and
1599  // it so happens that PAD_ID in Cadstar is a sequential, numerical ID
1600  m->Pads().at( pin.PadID - (long) 1 )->SetNet( getKiCadNet( net.ID ) );
1601  }
1602  }
1603  }
1604 }
1605 
1606 
1608  const COMPONENT& aComponent, MODULE* aModule )
1609 {
1610  for( std::pair<ATTRIBUTE_ID, ATTRIBUTE_VALUE> attrPair : aComponent.AttributeValues )
1611  {
1612  ATTRIBUTE_VALUE& attrval = attrPair.second;
1613 
1614  if( attrval.HasLocation ) //only import attributes with location. Ignore the rest
1615  addAttribute( attrval.AttributeLocation, attrval.AttributeID, aModule, attrval.Value );
1616  }
1617 
1618  for( std::pair<ATTRIBUTE_ID, TEXT_LOCATION> textlocPair : aComponent.TextLocations )
1619  {
1620  TEXT_LOCATION& textloc = textlocPair.second;
1621  wxString attrval;
1622 
1623  if( textloc.AttributeID == COMPONENT_NAME_ATTRID )
1624  {
1625  attrval = wxEmptyString; // Designator is loaded separately
1626  }
1627  else if( textloc.AttributeID == COMPONENT_NAME_2_ATTRID )
1628  {
1629  attrval = wxT( "${REFERENCE}" );
1630  }
1631  else if( textloc.AttributeID == PART_NAME_ATTRID )
1632  {
1633  attrval = getPart( aComponent.PartID ).Name;
1634  }
1635  else
1636  attrval = getAttributeValue( textloc.AttributeID, aComponent.AttributeValues );
1637 
1638  addAttribute( textloc, textloc.AttributeID, aModule, attrval );
1639  }
1640 }
1641 
1642 
1644  const NET_ID& aCadstarNetID, const NET_PCB::ROUTE& aCadstarRoute )
1645 {
1646  std::vector<PCB_SHAPE*> shapes;
1647 
1648  POINT prevEnd = aCadstarRoute.StartPoint;
1649 
1650  for( const NET_PCB::ROUTE_VERTEX& v : aCadstarRoute.RouteVertices )
1651  {
1652  PCB_SHAPE* shape = getDrawSegmentFromVertex( prevEnd, v.Vertex );
1653  shape->SetLayer( getKiCadLayer( aCadstarRoute.LayerID ) );
1654  shape->SetWidth( getKiCadLength( v.RouteWidth ) );
1655  shapes.push_back( shape );
1656  prevEnd = v.Vertex.End;
1657  }
1658 
1659  //Todo add real netcode to the tracks
1660  std::vector<TRACK*> tracks =
1661  makeTracksFromDrawsegments( shapes, mBoard, getKiCadNet( aCadstarNetID ) );
1662 
1663  //cleanup
1664  for( PCB_SHAPE* shape : shapes )
1665  delete shape;
1666 }
1667 
1668 
1670  const NET_ID& aCadstarNetID, const NET_PCB::VIA& aCadstarVia )
1671 {
1672  VIA* via = new VIA( mBoard );
1673  mBoard->Add( via, ADD_MODE::APPEND );
1674 
1675  VIACODE csViaCode = getViaCode( aCadstarVia.ViaCodeID );
1676  LAYERPAIR csLayerPair = getLayerPair( aCadstarVia.LayerPairID );
1677 
1678  via->SetPosition( getKiCadPoint( aCadstarVia.Location ) );
1679  via->SetDrill( getKiCadLength( csViaCode.DrillDiameter ) );
1680  via->SetLocked( aCadstarVia.Fixed );
1681 
1682  if( csViaCode.Shape.ShapeType != PAD_SHAPE_TYPE::CIRCLE )
1683  wxLogError( wxString::Format(
1684  _( "The CADSTAR via code '%s' has different shape from a circle defined. "
1685  "KiCad only supports circular vias so this via type has been changed to "
1686  "be a via with circular shape of %.2f mm diameter." ),
1687  csViaCode.Name,
1688  (double) ( (double) getKiCadLength( csViaCode.Shape.Size ) / 1E6 ) ) );
1689 
1690  via->SetWidth( getKiCadLength( csViaCode.Shape.Size ) );
1691 
1692  bool start_layer_outside =
1693  csLayerPair.PhysicalLayerStart == 1
1695  bool end_layer_outside =
1696  csLayerPair.PhysicalLayerEnd == 1
1698 
1699  if( start_layer_outside && end_layer_outside )
1700  {
1701  via->SetViaType( VIATYPE::THROUGH );
1702  }
1703  else if( ( !start_layer_outside ) && ( !end_layer_outside ) )
1704  {
1706  }
1707  else
1708  {
1709  via->SetViaType( VIATYPE::MICROVIA );
1710  }
1711 
1713  getKiCadCopperLayerID( csLayerPair.PhysicalLayerEnd ) );
1714  via->SetNet( getKiCadNet( aCadstarNetID ) );
1716 }
1717 
1718 
1720  BOARD_ITEM_CONTAINER* aContainer, const GROUP_ID& aCadstarGroupID,
1721  const LAYER_ID& aCadstarLayerOverride, const wxPoint& aMoveVector,
1722  const double& aRotationAngle, const double& aScalingFactor, const wxPoint& aTransformCentre,
1723  const bool& aMirrorInvert )
1724 {
1725  PCB_TEXT* txt = new PCB_TEXT( aContainer );
1726  aContainer->Add( txt );
1727  txt->SetText( aCadstarText.Text );
1728 
1729  wxPoint rotatedTextPos = getKiCadPoint( aCadstarText.Position );
1730  RotatePoint( &rotatedTextPos, aTransformCentre, aRotationAngle );
1731  rotatedTextPos.x =
1732  KiROUND( (double) ( rotatedTextPos.x - aTransformCentre.x ) * aScalingFactor );
1733  rotatedTextPos.y =
1734  KiROUND( (double) ( rotatedTextPos.y - aTransformCentre.y ) * aScalingFactor );
1735  rotatedTextPos += aTransformCentre;
1736  txt->SetTextPos( rotatedTextPos );
1737  txt->SetPosition( rotatedTextPos );
1738 
1739  txt->SetTextAngle( getAngleTenthDegree( aCadstarText.OrientAngle ) + aRotationAngle );
1740 
1741  if( aCadstarText.Mirror != aMirrorInvert ) // If mirroring, invert angle to match CADSTAR
1742  txt->SetTextAngle( -txt->GetTextAngle() );
1743 
1744  txt->SetMirrored( aCadstarText.Mirror );
1745 
1746  TEXTCODE tc = getTextCode( aCadstarText.TextCodeID );
1747 
1749 
1750  wxSize unscaledTextSize;
1751  unscaledTextSize.x = getKiCadLength( tc.Width );
1752  unscaledTextSize.y = KiROUND( TXT_HEIGHT_RATIO * (double) getKiCadLength( tc.Height ) );
1753  txt->SetTextSize( unscaledTextSize );
1754 
1755  switch( aCadstarText.Alignment )
1756  {
1757  case ALIGNMENT::NO_ALIGNMENT: // Default for Single line text is Bottom Left
1758  case ALIGNMENT::BOTTOMLEFT:
1761  break;
1762 
1766  break;
1767 
1771  break;
1772 
1773  case ALIGNMENT::CENTERLEFT:
1776  break;
1777 
1781  break;
1782 
1786  break;
1787 
1788  case ALIGNMENT::TOPLEFT:
1791  break;
1792 
1793  case ALIGNMENT::TOPCENTER:
1796  break;
1797 
1798  case ALIGNMENT::TOPRIGHT:
1801  break;
1802 
1803  default:
1804  wxFAIL_MSG( "Unknown Aligment - needs review!" );
1805  }
1806 
1807  if( aMirrorInvert )
1808  {
1809  txt->Flip( aTransformCentre, true );
1810  }
1811 
1812  //scale it after flipping:
1813  if( aScalingFactor != 1.0 )
1814  {
1815  wxSize scaledTextSize;
1816  scaledTextSize.x = KiROUND( (double) getKiCadLength( tc.Width ) * aScalingFactor );
1817  scaledTextSize.y = KiROUND( (double) getKiCadLength( tc.Height ) * aScalingFactor );
1818  txt->SetTextSize( scaledTextSize );
1819  txt->SetTextThickness(
1820  KiROUND( (double) getKiCadLength( tc.LineWidth ) * aScalingFactor ) );
1821  }
1822 
1823  txt->Move( aMoveVector );
1824 
1825  LAYER_ID layersToDrawOn = aCadstarLayerOverride;
1826 
1827  if( layersToDrawOn.IsEmpty() )
1828  layersToDrawOn = aCadstarText.LayerID;
1829 
1830  if( isLayerSet( layersToDrawOn ) )
1831  {
1832  //Make a copy on each layer
1833 
1834  LSEQ layers = getKiCadLayerSet( layersToDrawOn ).Seq();
1835  PCB_TEXT* newtxt;
1836 
1837  for( PCB_LAYER_ID layer : layers )
1838  {
1839  txt->SetLayer( layer );
1840  newtxt = new PCB_TEXT( *txt );
1841  mBoard->Add( newtxt, ADD_MODE::APPEND );
1842 
1843  if( !aCadstarGroupID.IsEmpty() )
1844  addToGroup( aCadstarGroupID, newtxt );
1845  }
1846 
1847  mBoard->Remove( txt );
1848  delete txt;
1849  }
1850  else
1851  {
1852  txt->SetLayer( getKiCadLayer( layersToDrawOn ) );
1853 
1854  if( !aCadstarGroupID.IsEmpty() )
1855  addToGroup( aCadstarGroupID, txt );
1856  }
1857  //TODO Handle different font types when KiCad can support it.
1858 }
1859 
1860 
1862  const PCB_LAYER_ID& aKiCadLayer, const int& aLineThickness, const wxString& aShapeName,
1863  BOARD_ITEM_CONTAINER* aContainer, const GROUP_ID& aCadstarGroupID,
1864  const wxPoint& aMoveVector, const double& aRotationAngle, const double& aScalingFactor,
1865  const wxPoint& aTransformCentre, const bool& aMirrorInvert )
1866 {
1867  switch( aCadstarShape.Type )
1868  {
1869  case SHAPE_TYPE::OPENSHAPE:
1870  case SHAPE_TYPE::OUTLINE:
1872  drawCadstarVerticesAsSegments( aCadstarShape.Vertices, aKiCadLayer, aLineThickness,
1873  aContainer, aCadstarGroupID, aMoveVector, aRotationAngle, aScalingFactor,
1874  aTransformCentre, aMirrorInvert );
1875  drawCadstarCutoutsAsSegments( aCadstarShape.Cutouts, aKiCadLayer, aLineThickness,
1876  aContainer, aCadstarGroupID, aMoveVector, aRotationAngle, aScalingFactor,
1877  aTransformCentre, aMirrorInvert );
1878  break;
1879 
1880  case SHAPE_TYPE::HATCHED:
1882  wxLogWarning( wxString::Format(
1883  _( "The shape for '%s' is Hatch filled in CADSTAR, which has no KiCad equivalent. "
1884  "Using solid fill instead." ),
1885  aShapeName ) );
1886 
1887  case SHAPE_TYPE::SOLID:
1888  {
1889  PCB_SHAPE* shape;
1890 
1891  if( isModule( aContainer ) )
1892  shape = new FP_SHAPE( (MODULE*) aContainer, S_POLYGON );
1893  else
1894  {
1895  shape = new PCB_SHAPE( aContainer );
1896  shape->SetShape( S_POLYGON );
1897  }
1898 
1899  shape->SetPolyShape( getPolySetFromCadstarShape( aCadstarShape, -1, aContainer, aMoveVector,
1900  aRotationAngle, aScalingFactor, aTransformCentre, aMirrorInvert ) );
1901  shape->SetWidth( aLineThickness );
1902  shape->SetLayer( aKiCadLayer );
1903  aContainer->Add( shape, ADD_MODE::APPEND );
1904 
1905  if( !aCadstarGroupID.IsEmpty() )
1906  addToGroup( aCadstarGroupID, shape );
1907  }
1908  break;
1909  }
1910 }
1911 
1912 
1913 void CADSTAR_PCB_ARCHIVE_LOADER::drawCadstarCutoutsAsSegments( const std::vector<CUTOUT>& aCutouts,
1914  const PCB_LAYER_ID& aKiCadLayer, const int& aLineThickness,
1915  BOARD_ITEM_CONTAINER* aContainer, const GROUP_ID& aCadstarGroupID,
1916  const wxPoint& aMoveVector, const double& aRotationAngle, const double& aScalingFactor,
1917  const wxPoint& aTransformCentre, const bool& aMirrorInvert )
1918 {
1919  for( CUTOUT cutout : aCutouts )
1920  {
1921  drawCadstarVerticesAsSegments( cutout.Vertices, aKiCadLayer, aLineThickness, aContainer,
1922  aCadstarGroupID, aMoveVector, aRotationAngle, aScalingFactor, aTransformCentre,
1923  aMirrorInvert );
1924  }
1925 }
1926 
1927 
1929  const std::vector<VERTEX>& aCadstarVertices, const PCB_LAYER_ID& aKiCadLayer,
1930  const int& aLineThickness, BOARD_ITEM_CONTAINER* aContainer,
1931  const GROUP_ID& aCadstarGroupID, const wxPoint& aMoveVector, const double& aRotationAngle,
1932  const double& aScalingFactor, const wxPoint& aTransformCentre, const bool& aMirrorInvert )
1933 {
1934  std::vector<PCB_SHAPE*> drawSegments =
1935  getDrawSegmentsFromVertices( aCadstarVertices, aContainer, aCadstarGroupID, aMoveVector,
1936  aRotationAngle, aScalingFactor, aTransformCentre, aMirrorInvert );
1937 
1938  for( PCB_SHAPE* ds : drawSegments )
1939  {
1940  ds->SetWidth( aLineThickness );
1941  ds->SetLayer( aKiCadLayer );
1942  ds->SetParent( aContainer );
1943  aContainer->Add( ds, ADD_MODE::APPEND );
1944  }
1945 }
1946 
1947 
1949  const std::vector<VERTEX>& aCadstarVertices, BOARD_ITEM_CONTAINER* aContainer,
1950  const GROUP_ID& aCadstarGroupID, const wxPoint& aMoveVector, const double& aRotationAngle,
1951  const double& aScalingFactor, const wxPoint& aTransformCentre, const bool& aMirrorInvert )
1952 {
1953  std::vector<PCB_SHAPE*> drawSegments;
1954 
1955  if( aCadstarVertices.size() < 2 )
1956  //need at least two points to draw a segment! (unlikely but possible to have only one)
1957  return drawSegments;
1958 
1959  const VERTEX* prev = &aCadstarVertices.at( 0 ); // first one should always be a point vertex
1960  const VERTEX* cur;
1961 
1962  for( size_t i = 1; i < aCadstarVertices.size(); i++ )
1963  {
1964  cur = &aCadstarVertices.at( i );
1965  drawSegments.push_back(
1966  getDrawSegmentFromVertex( prev->End, *cur, aContainer, aCadstarGroupID, aMoveVector,
1967  aRotationAngle, aScalingFactor, aTransformCentre, aMirrorInvert ) );
1968  prev = cur;
1969  }
1970 
1971  return drawSegments;
1972 }
1973 
1974 
1976  const VERTEX& aCadstarVertex,
1977  BOARD_ITEM_CONTAINER* aContainer,
1978  const GROUP_ID& aCadstarGroupID,
1979  const wxPoint& aMoveVector,
1980  const double& aRotationAngle,
1981  const double& aScalingFactor,
1982  const wxPoint& aTransformCentre,
1983  const bool& aMirrorInvert )
1984 {
1985  PCB_SHAPE* ds = nullptr;
1986  bool cw = false;
1987  double arcStartAngle, arcEndAngle, arcAngle;
1988 
1989  wxPoint startPoint = getKiCadPoint( aCadstarStartPoint );
1990  wxPoint endPoint = getKiCadPoint( aCadstarVertex.End );
1991  wxPoint centerPoint;
1992 
1993  if( aCadstarVertex.Type == VERTEX_TYPE::ANTICLOCKWISE_SEMICIRCLE
1994  || aCadstarVertex.Type == VERTEX_TYPE::CLOCKWISE_SEMICIRCLE )
1995  centerPoint = ( startPoint + endPoint ) / 2;
1996  else
1997  centerPoint = getKiCadPoint( aCadstarVertex.Center );
1998 
1999  switch( aCadstarVertex.Type )
2000  {
2001 
2002  case VERTEX_TYPE::POINT:
2003 
2004  if( isModule( aContainer ) )
2005  {
2006  ds = new FP_SHAPE( static_cast<MODULE*>( aContainer ), S_SEGMENT );
2007  }
2008  else
2009  {
2010  ds = new PCB_SHAPE( aContainer );
2011  ds->SetShape( S_SEGMENT );
2012  }
2013 
2014  ds->SetStart( startPoint );
2015  ds->SetEnd( endPoint );
2016  break;
2017 
2020  cw = true;
2022 
2025 
2026  if( isModule( aContainer ) )
2027  {
2028  ds = new FP_SHAPE((MODULE*) aContainer, S_ARC );
2029  }
2030  else
2031  {
2032  ds = new PCB_SHAPE( aContainer );
2033  ds->SetShape( S_ARC );
2034  }
2035 
2036  ds->SetArcStart( startPoint );
2037  ds->SetCenter( centerPoint );
2038 
2039  arcStartAngle = getPolarAngle( startPoint - centerPoint );
2040  arcEndAngle = getPolarAngle( endPoint - centerPoint );
2041  arcAngle = arcEndAngle - arcStartAngle;
2042  //TODO: detect if we are supposed to draw a circle instead (i.e. two SEMICIRCLEs
2043  // with opposite start/end points and same centre point)
2044 
2045  if( cw )
2046  ds->SetAngle( NormalizeAnglePos( arcAngle ) );
2047  else
2048  ds->SetAngle( NormalizeAngleNeg( arcAngle ) );
2049 
2050  break;
2051  }
2052 
2053  //Apply transforms
2054  if( aMirrorInvert )
2055  ds->Flip( aTransformCentre, true );
2056 
2057  if( aScalingFactor != 1.0 )
2058  {
2059  ds->Move( -aTransformCentre );
2060  ds->Scale( aScalingFactor );
2061  ds->Move( aTransformCentre );
2062  }
2063 
2064  if( aRotationAngle != 0.0 )
2065  ds->Rotate( aTransformCentre, aRotationAngle );
2066 
2067  if( aMoveVector != wxPoint{ 0, 0 } )
2068  ds->Move( aMoveVector );
2069 
2070  if( isModule( aContainer ) && ds != nullptr )
2071  static_cast<FP_SHAPE*>( ds )->SetLocalCoord();
2072 
2073  if( !aCadstarGroupID.IsEmpty() )
2074  addToGroup( aCadstarGroupID, ds );
2075 
2076  return ds;
2077 }
2078 
2079 
2081  const int& aLineThickness, BOARD_ITEM_CONTAINER* aParentContainer )
2082 {
2083  ZONE_CONTAINER* zone = new ZONE_CONTAINER( aParentContainer, isModule( aParentContainer ) );
2084 
2085  if( aCadstarShape.Type == SHAPE_TYPE::HATCHED )
2086  {
2089  }
2090  else
2091  {
2093  }
2094 
2095  SHAPE_POLY_SET polygon = getPolySetFromCadstarShape( aCadstarShape, aLineThickness );
2096 
2097  zone->AddPolygon( polygon.COutline( 0 ) );
2098 
2099  for( int i = 0; i < polygon.HoleCount( 0 ); i++ )
2100  zone->AddPolygon( polygon.CHole( 0, i ) );
2101 
2102  return zone;
2103 }
2104 
2105 
2107  const int& aLineThickness, BOARD_ITEM_CONTAINER* aContainer, const wxPoint& aMoveVector,
2108  const double& aRotationAngle, const double& aScalingFactor, const wxPoint& aTransformCentre,
2109  const bool& aMirrorInvert )
2110 {
2111  GROUP_ID noGroup = wxEmptyString;
2112 
2113  std::vector<PCB_SHAPE*> outlineSegments =
2114  getDrawSegmentsFromVertices( aCadstarShape.Vertices, aContainer, noGroup, aMoveVector,
2115  aRotationAngle, aScalingFactor, aTransformCentre, aMirrorInvert );
2116 
2117  SHAPE_POLY_SET polySet( getLineChainFromDrawsegments( outlineSegments ) );
2118 
2119  //cleanup
2120  for( PCB_SHAPE* seg : outlineSegments )
2121  delete seg;
2122 
2123  for( CUTOUT cutout : aCadstarShape.Cutouts )
2124  {
2125  std::vector<PCB_SHAPE*> cutoutSeg =
2126  getDrawSegmentsFromVertices( cutout.Vertices, aContainer, noGroup, aMoveVector,
2127  aRotationAngle, aScalingFactor, aTransformCentre, aMirrorInvert );
2128 
2129  polySet.AddHole( getLineChainFromDrawsegments( cutoutSeg ) );
2130 
2131  //cleanup
2132  for( PCB_SHAPE* seg : cutoutSeg )
2133  delete seg;
2134  }
2135 
2136  if( aLineThickness > 0 )
2137  polySet.Inflate(
2138  aLineThickness / 2, 32, SHAPE_POLY_SET::CORNER_STRATEGY::ROUND_ALL_CORNERS );
2139 
2140  //Make a new polyset with no holes
2141  //TODO: Using strictly simple to be safe, but need to find out if PM_FAST works okay
2142  polySet.Fracture( SHAPE_POLY_SET::POLYGON_MODE::PM_STRICTLY_SIMPLE );
2143 
2144 #ifdef DEBUG
2145  for( int i = 0; i < polySet.OutlineCount(); ++i )
2146  {
2147  wxASSERT( polySet.Outline( i ).PointCount() > 2 );
2148 
2149  for( int j = 0; j < polySet.HoleCount( i ); ++j )
2150  {
2151  wxASSERT( polySet.Hole( i, j ).PointCount() > 2 );
2152  }
2153  }
2154 #endif
2155 
2156  return polySet;
2157 }
2158 
2159 
2161  const std::vector<PCB_SHAPE*> aDrawsegments )
2162 {
2163  SHAPE_LINE_CHAIN lineChain;
2164 
2165  for( PCB_SHAPE* ds : aDrawsegments )
2166  {
2167  switch( ds->GetShape() )
2168  {
2169  case S_ARC:
2170  {
2171  if( ds->GetClass() == wxT( "MGRAPHIC" ) )
2172  {
2173  FP_SHAPE* em = (FP_SHAPE*) ds;
2174  SHAPE_ARC arc( em->GetStart0(), em->GetEnd0(), (double) em->GetAngle() / 10.0 );
2175  lineChain.Append( arc );
2176  }
2177  else
2178  {
2179  SHAPE_ARC arc( ds->GetCenter(), ds->GetArcStart(), (double) ds->GetAngle() / 10.0 );
2180  lineChain.Append( arc );
2181  }
2182  }
2183  break;
2184  case S_SEGMENT:
2185  if( ds->GetClass() == wxT( "MGRAPHIC" ) )
2186  {
2187  FP_SHAPE* em = (FP_SHAPE*) ds;
2188  lineChain.Append( em->GetStart0().x, em->GetStart0().y );
2189  lineChain.Append( em->GetEnd0().x, em->GetEnd0().y );
2190  }
2191  else
2192  {
2193  lineChain.Append( ds->GetStartX(), ds->GetStartY() );
2194  lineChain.Append( ds->GetEndX(), ds->GetEndY() );
2195  }
2196  break;
2197 
2198  default:
2199  wxFAIL_MSG( "Drawsegment type is unexpected. Ignored." );
2200  }
2201  }
2202 
2203  lineChain.SetClosed( true ); //todo check if it is closed
2204 
2205  wxASSERT( lineChain.PointCount() > 2 );
2206 
2207  return lineChain;
2208 }
2209 
2210 
2212  const std::vector<PCB_SHAPE*> aDrawsegments,
2213  BOARD_ITEM_CONTAINER* aParentContainer,
2214  NETINFO_ITEM* aNet, PCB_LAYER_ID aLayerOverride,
2215  int aWidthOverride )
2216 {
2217  std::vector<TRACK*> tracks;
2218 
2219  for( PCB_SHAPE* ds : aDrawsegments )
2220  {
2221  TRACK* track;
2222 
2223  switch( ds->GetShape() )
2224  {
2225  case S_ARC:
2226  if( ds->GetClass() == wxT( "MGRAPHIC" ) )
2227  {
2228  FP_SHAPE* em = (FP_SHAPE*) ds;
2229  SHAPE_ARC arc( em->GetStart0(), em->GetEnd0(), (double) em->GetAngle() / 10.0 );
2230  track = new ARC( aParentContainer, &arc );
2231  }
2232  else
2233  {
2234  SHAPE_ARC arc( ds->GetCenter(), ds->GetArcStart(), (double) ds->GetAngle() / 10.0 );
2235  track = new ARC( aParentContainer, &arc );
2236  }
2237  break;
2238  case S_SEGMENT:
2239  if( ds->GetClass() == wxT( "MGRAPHIC" ) )
2240  {
2241  FP_SHAPE* em = (FP_SHAPE*) ds;
2242  track = new TRACK( aParentContainer );
2243  track->SetStart( em->GetStart0() );
2244  track->SetEnd( em->GetEnd0() );
2245  }
2246  else
2247  {
2248  track = new TRACK( aParentContainer );
2249  track->SetStart( ds->GetStart() );
2250  track->SetEnd( ds->GetEnd() );
2251  }
2252  break;
2253 
2254  default:
2255  wxFAIL_MSG( "Drawsegment type is unexpected. Ignored." );
2256  continue;
2257  }
2258 
2259  if( aWidthOverride == -1 )
2260  track->SetWidth( ds->GetWidth() );
2261  else
2262  track->SetWidth( aWidthOverride );
2263 
2264  if( aLayerOverride == PCB_LAYER_ID::UNDEFINED_LAYER )
2265  track->SetLayer( ds->GetLayer() );
2266  else
2267  track->SetLayer( aLayerOverride );
2268 
2269  if( aNet != nullptr )
2270  track->SetNet( aNet );
2271 
2272  tracks.push_back( track );
2273  aParentContainer->Add( track, ADD_MODE::APPEND );
2274  }
2275 
2276  return tracks;
2277 }
2278 
2279 
2281  const ATTRIBUTE_ID& aCadstarAttributeID, MODULE* aModule, const wxString& aAttributeValue )
2282 {
2283  FP_TEXT* txt;
2284 
2285  if( aCadstarAttributeID == COMPONENT_NAME_ATTRID )
2286  {
2287  txt = &aModule->Reference(); //text should be set outside this function
2288  }
2289  else if( aCadstarAttributeID == PART_NAME_ATTRID )
2290  {
2291  if( aModule->Value().GetText().IsEmpty() )
2292  {
2293  // Use PART_NAME_ATTRID as the value is value field is blank
2294  aModule->SetValue( aAttributeValue );
2295  txt = &aModule->Value();
2296  }
2297  else
2298  {
2299  txt = new FP_TEXT( aModule );
2300  aModule->Add( txt );
2301  txt->SetText( aAttributeValue );
2302  }
2303  txt->SetVisible( false ); //make invisible to avoid clutter.
2304  }
2305  else if( aCadstarAttributeID != COMPONENT_NAME_2_ATTRID
2306  && getAttributeName( aCadstarAttributeID ) == wxT( "Value" ) )
2307  {
2308  if( !aModule->Value().GetText().IsEmpty() )
2309  {
2310  //copy the object
2311  aModule->Add( new FP_TEXT( aModule->Value() ) );
2312  }
2313 
2314  aModule->SetValue( aAttributeValue );
2315  txt = &aModule->Value();
2316  txt->SetVisible( false ); //make invisible to avoid clutter.
2317  }
2318  else
2319  {
2320  txt = new FP_TEXT( aModule );
2321  aModule->Add( txt );
2322  txt->SetText( aAttributeValue );
2323  txt->SetVisible( false ); //make all user attributes invisible to avoid clutter.
2324  //TODO: Future improvement - allow user to decide what to do with attributes
2325  }
2326 
2327  wxPoint rotatedTextPos = getKiCadPoint( aCadstarAttrLoc.Position ) - aModule->GetPosition();
2328  RotatePoint( &rotatedTextPos, -aModule->GetOrientation() );
2329 
2330  txt->SetTextPos( getKiCadPoint( aCadstarAttrLoc.Position ) );
2331  txt->SetPos0( rotatedTextPos );
2332  txt->SetLayer( getKiCadLayer( aCadstarAttrLoc.LayerID ) );
2333  txt->SetMirrored( aCadstarAttrLoc.Mirror );
2334  txt->SetTextAngle(
2335  getAngleTenthDegree( aCadstarAttrLoc.OrientAngle ) - aModule->GetOrientation() );
2336 
2337  if( aCadstarAttrLoc.Mirror ) // If mirroring, invert angle to match CADSTAR
2338  txt->SetTextAngle( -txt->GetTextAngle() );
2339 
2340  TEXTCODE tc = getTextCode( aCadstarAttrLoc.TextCodeID );
2341 
2343 
2344  wxSize txtSize;
2345  txtSize.x = getKiCadLength( tc.Width );
2346  txtSize.y = KiROUND( TXT_HEIGHT_RATIO * (double) getKiCadLength( tc.Height ) );
2347  txt->SetTextSize( txtSize );
2348 
2349  switch( aCadstarAttrLoc.Alignment )
2350  {
2351  case ALIGNMENT::NO_ALIGNMENT: // Default for Single line text is Bottom Left
2352  case ALIGNMENT::BOTTOMLEFT:
2355  break;
2356 
2360  break;
2361 
2365  break;
2366 
2367  case ALIGNMENT::CENTERLEFT:
2370  break;
2371 
2375  break;
2376 
2380  break;
2381 
2382  case ALIGNMENT::TOPLEFT:
2385  break;
2386 
2387  case ALIGNMENT::TOPCENTER:
2390  break;
2391 
2392  case ALIGNMENT::TOPRIGHT:
2395  break;
2396 
2397  default:
2398  wxFAIL_MSG( "Unknown Aligment - needs review!" );
2399  }
2400 
2401  //TODO Handle different font types when KiCad can support it.
2402 }
2403 
2404 
2406 {
2407  wxCHECK( Assignments.Codedefs.LineCodes.find( aCadstarLineCodeID )
2408  != Assignments.Codedefs.LineCodes.end(),
2409  mBoard->GetDesignSettings().GetLineThickness( PCB_LAYER_ID::Edge_Cuts ) );
2410 
2411  return getKiCadLength( Assignments.Codedefs.LineCodes.at( aCadstarLineCodeID ).Width );
2412 }
2413 
2414 
2416  const COPPERCODE_ID& aCadstaCopperCodeID )
2417 {
2418  wxCHECK( Assignments.Codedefs.CopperCodes.find( aCadstaCopperCodeID )
2419  != Assignments.Codedefs.CopperCodes.end(),
2420  COPPERCODE() );
2421 
2422  return Assignments.Codedefs.CopperCodes.at( aCadstaCopperCodeID );
2423 }
2424 
2425 
2427  const TEXTCODE_ID& aCadstarTextCodeID )
2428 {
2429  wxCHECK( Assignments.Codedefs.TextCodes.find( aCadstarTextCodeID )
2430  != Assignments.Codedefs.TextCodes.end(),
2431  TEXTCODE() );
2432 
2433  return Assignments.Codedefs.TextCodes.at( aCadstarTextCodeID );
2434 }
2435 
2436 
2438  const PADCODE_ID& aCadstarPadCodeID )
2439 {
2440  wxCHECK( Assignments.Codedefs.PadCodes.find( aCadstarPadCodeID )
2441  != Assignments.Codedefs.PadCodes.end(),
2442  PADCODE() );
2443 
2444  return Assignments.Codedefs.PadCodes.at( aCadstarPadCodeID );
2445 }
2446 
2447 
2449  const VIACODE_ID& aCadstarViaCodeID )
2450 {
2451  wxCHECK( Assignments.Codedefs.ViaCodes.find( aCadstarViaCodeID )
2452  != Assignments.Codedefs.ViaCodes.end(),
2453  VIACODE() );
2454 
2455  return Assignments.Codedefs.ViaCodes.at( aCadstarViaCodeID );
2456 }
2457 
2458 
2460  const LAYERPAIR_ID& aCadstarLayerPairID )
2461 {
2462  wxCHECK( Assignments.Codedefs.LayerPairs.find( aCadstarLayerPairID )
2463  != Assignments.Codedefs.LayerPairs.end(),
2464  LAYERPAIR() );
2465 
2466  return Assignments.Codedefs.LayerPairs.at( aCadstarLayerPairID );
2467 }
2468 
2469 
2470 wxString CADSTAR_PCB_ARCHIVE_LOADER::getAttributeName( const ATTRIBUTE_ID& aCadstarAttributeID )
2471 {
2472  wxCHECK( Assignments.Codedefs.AttributeNames.find( aCadstarAttributeID )
2474  wxEmptyString );
2475 
2476  return Assignments.Codedefs.AttributeNames.at( aCadstarAttributeID ).Name;
2477 }
2478 
2479 
2481  const std::map<ATTRIBUTE_ID, ATTRIBUTE_VALUE>& aCadstarAttributeMap )
2482 {
2483  wxCHECK( aCadstarAttributeMap.find( aCadstarAttributeID ) != aCadstarAttributeMap.end(),
2484  wxEmptyString );
2485 
2486  return aCadstarAttributeMap.at( aCadstarAttributeID ).Value;
2487 }
2488 
2489 
2491  const PART_ID& aCadstarPartID )
2492 {
2493  wxCHECK( Parts.PartDefinitions.find( aCadstarPartID ) != Parts.PartDefinitions.end(), PART() );
2494 
2495  return Parts.PartDefinitions.at( aCadstarPartID );
2496 }
2497 
2498 
2500  const ROUTECODE_ID& aCadstarRouteCodeID )
2501 {
2502  wxCHECK( Assignments.Codedefs.RouteCodes.find( aCadstarRouteCodeID )
2503  != Assignments.Codedefs.RouteCodes.end(),
2504  ROUTECODE() );
2505 
2506  return Assignments.Codedefs.RouteCodes.at( aCadstarRouteCodeID );
2507 }
2508 
2509 
2511  const HATCHCODE_ID& aCadstarHatchcodeID )
2512 {
2513  wxCHECK( Assignments.Codedefs.HatchCodes.find( aCadstarHatchcodeID )
2514  != Assignments.Codedefs.HatchCodes.end(),
2515  HATCHCODE() );
2516 
2517  return Assignments.Codedefs.HatchCodes.at( aCadstarHatchcodeID );
2518 }
2519 
2520 
2522  const HATCHCODE_ID& aCadstarHatchcodeID )
2523 {
2524  checkAndLogHatchCode( aCadstarHatchcodeID );
2525  HATCHCODE hcode = getHatchCode( aCadstarHatchcodeID );
2526 
2527  if( hcode.Hatches.size() < 1 )
2528  return mBoard->GetDesignSettings().GetDefaultZoneSettings().m_HatchOrientation;
2529  else
2530  return getAngleDegrees( hcode.Hatches.at( 0 ).OrientAngle );
2531 }
2532 
2533 
2535  const HATCHCODE_ID& aCadstarHatchcodeID )
2536 {
2537  checkAndLogHatchCode( aCadstarHatchcodeID );
2538  HATCHCODE hcode = getHatchCode( aCadstarHatchcodeID );
2539 
2540  if( hcode.Hatches.size() < 1 )
2541  return mBoard->GetDesignSettings().GetDefaultZoneSettings().m_HatchThickness;
2542  else
2543  return getKiCadLength( hcode.Hatches.at( 0 ).LineWidth );
2544 }
2545 
2546 
2548 {
2549  checkAndLogHatchCode( aCadstarHatchcodeID );
2550  HATCHCODE hcode = getHatchCode( aCadstarHatchcodeID );
2551 
2552  if( hcode.Hatches.size() < 1 )
2553  return mBoard->GetDesignSettings().GetDefaultZoneSettings().m_HatchGap;
2554  else
2555  return getKiCadLength( hcode.Hatches.at( 0 ).Step );
2556 }
2557 
2558 
2560 {
2561  wxCHECK( mGroupMap.find( aCadstarGroupID ) != mGroupMap.end(), nullptr );
2562 
2563  return mGroupMap.at( aCadstarGroupID );
2564 }
2565 
2566 
2568 {
2569  if( mHatchcodesTested.find( aCadstarHatchcodeID ) != mHatchcodesTested.end() )
2570  {
2571  return; //already checked
2572  }
2573  else
2574  {
2575  HATCHCODE hcode = getHatchCode( aCadstarHatchcodeID );
2576 
2577  if( hcode.Hatches.size() != 2 )
2578  {
2579  wxLogWarning( wxString::Format(
2580  _( "The CADSTAR Hatching code '%s' has %d hatches defined. "
2581  "KiCad only supports 2 hatches (crosshatching) 90 degrees apart. "
2582  "The imported hatching is crosshatched." ),
2583  hcode.Name, (int) hcode.Hatches.size() ) );
2584  }
2585  else
2586  {
2587  if( hcode.Hatches.at( 0 ).LineWidth != hcode.Hatches.at( 1 ).LineWidth )
2588  {
2589  wxLogWarning( wxString::Format(
2590  _( "The CADSTAR Hatching code '%s' has different line widths for each "
2591  "hatch. KiCad only supports one width for the haching. The imported "
2592  "hatching uses the width defined in the first hatch definition, i.e. "
2593  "%.2f mm." ),
2594  hcode.Name,
2595  (double) ( (double) getKiCadLength( hcode.Hatches.at( 0 ).LineWidth ) )
2596  / 1E6 ) );
2597  }
2598 
2599  if( hcode.Hatches.at( 0 ).Step != hcode.Hatches.at( 1 ).Step )
2600  {
2601  wxLogWarning( wxString::Format(
2602  _( "The CADSTAR Hatching code '%s' has different step sizes for each "
2603  "hatch. KiCad only supports one step size for the haching. The imported "
2604  "hatching uses the step size defined in the first hatching definition, "
2605  "i.e. %.2f mm." ),
2606  hcode.Name,
2607  (double) ( (double) getKiCadLength( hcode.Hatches.at( 0 ).Step ) )
2608  / 1E6 ) );
2609  }
2610 
2611  if( abs( hcode.Hatches.at( 0 ).OrientAngle - hcode.Hatches.at( 1 ).OrientAngle )
2612  != 90000 )
2613  {
2614  wxLogWarning( wxString::Format(
2615  _( "The hatches in CADSTAR Hatching code '%s' have an angle "
2616  "difference of %.1f degrees. KiCad only supports hatching 90 "
2617  "degrees apart. The imported hatching has two hatches 90 "
2618  "degrees apart, oriented %.1f degrees from horizontal." ),
2619  hcode.Name,
2620  getAngleDegrees( abs( hcode.Hatches.at( 0 ).OrientAngle
2621  - hcode.Hatches.at( 1 ).OrientAngle ) ),
2622  getAngleDegrees( hcode.Hatches.at( 0 ).OrientAngle ) ) );
2623  }
2624  }
2625 
2626  mHatchcodesTested.insert( aCadstarHatchcodeID );
2627  }
2628 }
2629 
2630 
2632  const COMPONENT_ID& aCadstarComponentID )
2633 {
2634  if( mComponentMap.find( aCadstarComponentID ) == mComponentMap.end() )
2635  return nullptr;
2636  else
2637  return mComponentMap.at( aCadstarComponentID );
2638 }
2639 
2640 
2641 wxPoint CADSTAR_PCB_ARCHIVE_LOADER::getKiCadPoint( wxPoint aCadstarPoint )
2642 {
2643  wxPoint retval;
2644 
2645  retval.x = ( aCadstarPoint.x - mDesignCenter.x ) * KiCadUnitMultiplier;
2646  retval.y = -( aCadstarPoint.y - mDesignCenter.y ) * KiCadUnitMultiplier;
2647 
2648  return retval;
2649 }
2650 
2651 
2653 {
2654 
2655  return NormalizeAnglePos( ArcTangente( aPoint.y, aPoint.x ) );
2656 }
2657 
2658 
2660 {
2661  if( aCadstarNetID.IsEmpty() )
2662  return nullptr;
2663  else if( mNetMap.find( aCadstarNetID ) != mNetMap.end() )
2664  {
2665  return mNetMap.at( aCadstarNetID );
2666  }
2667  else
2668  {
2669  wxCHECK( Layout.Nets.find( aCadstarNetID ) != Layout.Nets.end(), nullptr );
2670 
2671  NET_PCB csNet = Layout.Nets.at( aCadstarNetID );
2672  wxString newName = csNet.Name;
2673 
2674  if( csNet.Name.IsEmpty() )
2675  {
2676  if( csNet.Pins.size() > 0 )
2677  {
2678  // Create default KiCad net naming:
2679 
2680  NET_PCB::PIN firstPin = ( *csNet.Pins.begin() ).second;
2681  //we should have already loaded the component with loadComponents() :
2682  MODULE* m = getModuleFromCadstarID( firstPin.ComponentID );
2683  newName = wxT( "Net-(" );
2684  newName << m->Reference().GetText();
2685  newName << "-Pad" << wxString::Format( "%ld", firstPin.PadID ) << ")";
2686  }
2687  else
2688  {
2689  wxFAIL_MSG( "A net with no pins associated?" );
2690  newName = wxT( "csNet-" );
2691  newName << wxString::Format( "%i", csNet.SignalNum );
2692  }
2693  }
2694 
2695  if( !mDoneNetClassWarning && !csNet.NetClassID.IsEmpty()
2696  && csNet.NetClassID != wxT( "NONE" ) )
2697  {
2698  wxLogMessage(
2699  _( "The CADSTAR design contains nets with a 'Net Class' assigned. KiCad does "
2700  "not have an equivalent to CADSTAR's Net Class so these elements were not "
2701  "imported. Note: KiCad's version of 'Net Class' is closer to CADSTAR's "
2702  "'Net Route Code' (which has been imported for all nets)." ) );
2703  mDoneNetClassWarning = true;
2704  }
2705 
2706  if( !mDoneSpacingClassWarning && !csNet.SpacingClassID.IsEmpty()
2707  && csNet.SpacingClassID != wxT( "NONE" ) )
2708  {
2709  wxLogWarning( _(
2710  "The CADSTAR design contains nets with a 'Spacing Class' assigned. KiCad does "
2711  "not have an equivalent to CADSTAR's Spacing Class so these elements were not "
2712  "imported. Please review the design rules as copper pours will affected by "
2713  "this." ) );
2714  mDoneSpacingClassWarning = true;
2715  }
2716 
2717  NETINFO_ITEM* netInfo = new NETINFO_ITEM( mBoard, newName, ++mNumNets );
2718  mBoard->Add( netInfo, ADD_MODE::APPEND );
2719 
2720  if( mNetClassMap.find( csNet.RouteCodeID ) != mNetClassMap.end() )
2721  {
2722  NETCLASSPTR netclass = mNetClassMap.at( csNet.RouteCodeID );
2723  netInfo->SetClass( netclass );
2724  }
2725  else
2726  {
2727  ROUTECODE rc = getRouteCode( csNet.RouteCodeID );
2728  NETCLASSPTR netclass( new ::NETCLASS( rc.Name ) );
2729  netclass->SetTrackWidth( getKiCadLength( rc.OptimalWidth ) );
2730  netInfo->SetClass( netclass );
2731  mNetClassMap.insert( { csNet.RouteCodeID, netclass } );
2732  }
2733 
2734  mNetMap.insert( { aCadstarNetID, netInfo } );
2735  return netInfo;
2736  }
2737 
2738  return nullptr;
2739 }
2740 
2741 
2743 {
2744  if( aLayerNum == Assignments.Technology.MaxPhysicalLayer )
2745  return PCB_LAYER_ID::B_Cu;
2746 
2747  switch( aLayerNum )
2748  {
2749  case 1: return PCB_LAYER_ID::F_Cu;
2750  case 2: return PCB_LAYER_ID::In1_Cu;
2751  case 3: return PCB_LAYER_ID::In2_Cu;
2752  case 4: return PCB_LAYER_ID::In3_Cu;
2753  case 5: return PCB_LAYER_ID::In4_Cu;
2754  case 6: return PCB_LAYER_ID::In5_Cu;
2755  case 7: return PCB_LAYER_ID::In6_Cu;
2756  case 8: return PCB_LAYER_ID::In7_Cu;
2757  case 9: return PCB_LAYER_ID::In8_Cu;
2758  case 10: return PCB_LAYER_ID::In9_Cu;
2759  case 11: return PCB_LAYER_ID::In10_Cu;
2760  case 12: return PCB_LAYER_ID::In11_Cu;
2761  case 13: return PCB_LAYER_ID::In12_Cu;
2762  case 14: return PCB_LAYER_ID::In13_Cu;
2763  case 15: return PCB_LAYER_ID::In14_Cu;
2764  case 16: return PCB_LAYER_ID::In15_Cu;
2765  case 17: return PCB_LAYER_ID::In16_Cu;
2766  case 18: return PCB_LAYER_ID::In17_Cu;
2767  case 19: return PCB_LAYER_ID::In18_Cu;
2768  case 20: return PCB_LAYER_ID::In19_Cu;
2769  case 21: return PCB_LAYER_ID::In20_Cu;
2770  case 22: return PCB_LAYER_ID::In21_Cu;
2771  case 23: return PCB_LAYER_ID::In22_Cu;
2772  case 24: return PCB_LAYER_ID::In23_Cu;
2773  case 25: return PCB_LAYER_ID::In24_Cu;
2774  case 26: return PCB_LAYER_ID::In25_Cu;
2775  case 27: return PCB_LAYER_ID::In26_Cu;
2776  case 28: return PCB_LAYER_ID::In27_Cu;
2777  case 29: return PCB_LAYER_ID::In28_Cu;
2778  case 30: return PCB_LAYER_ID::In29_Cu;
2779  case 31: return PCB_LAYER_ID::In30_Cu;
2780  case 32: return PCB_LAYER_ID::B_Cu;
2781  }
2782 
2784 }
2785 
2786 bool CADSTAR_PCB_ARCHIVE_LOADER::isLayerSet( const LAYER_ID& aCadstarLayerID )
2787 {
2788  wxCHECK( Assignments.Layerdefs.Layers.find( aCadstarLayerID )
2789  != Assignments.Layerdefs.Layers.end(),
2790  false );
2791 
2792  LAYER& layer = Assignments.Layerdefs.Layers.at( aCadstarLayerID );
2793 
2794  switch( layer.Type )
2795  {
2796  case LAYER_TYPE::ALLDOC:
2797  case LAYER_TYPE::ALLELEC:
2798  case LAYER_TYPE::ALLLAYER:
2799  return true;
2800 
2801  default:
2802  return false;
2803  }
2804 
2805  return false;
2806 }
2807 
2808 
2810 {
2811  if( Assignments.Layerdefs.Layers.find( aCadstarLayerID ) != Assignments.Layerdefs.Layers.end() )
2812  {
2813  if( Assignments.Layerdefs.Layers.at( aCadstarLayerID ).Type == LAYER_TYPE::NOLAYER )
2814  //The "no layer" is common for CADSTAR documentation symbols
2815  //map it to undefined layer for later processing
2817  }
2818 
2819  wxCHECK( mLayermap.find( aCadstarLayerID ) != mLayermap.end(), PCB_LAYER_ID::UNDEFINED_LAYER );
2820 
2821  return mLayermap.at( aCadstarLayerID );
2822 }
2823 
2824 
2826 {
2827  LAYER& layer = Assignments.Layerdefs.Layers.at( aCadstarLayerID );
2828 
2829  switch( layer.Type )
2830  {
2831  case LAYER_TYPE::ALLDOC:
2834 
2835  case LAYER_TYPE::ALLELEC:
2836  return LSET::AllCuMask();
2837 
2838  case LAYER_TYPE::ALLLAYER:
2839  return LSET::AllLayersMask();
2840 
2841  default:
2842  return LSET( getKiCadLayer( aCadstarLayerID ) );
2843  }
2844 }
2845 
2846 
2848  const GROUP_ID& aCadstarGroupID, BOARD_ITEM* aKiCadItem )
2849 {
2850  wxCHECK( mGroupMap.find( aCadstarGroupID ) != mGroupMap.end(), );
2851 
2852  PCB_GROUP* parentGroup = mGroupMap.at( aCadstarGroupID );
2853  parentGroup->AddItem( aKiCadItem );
2854 }
2855 
2856 
2858  const wxString& aName )
2859 {
2860  wxString groupName = aName;
2861  int num = 0;
2862 
2863  while( mGroupMap.find( groupName ) != mGroupMap.end() )
2864  {
2865  groupName = aName + wxT( "_" ) + wxString::Format( "%i", ++num );
2866  }
2867 
2868  PCB_GROUP* docSymGroup = new PCB_GROUP( mBoard );
2869  mBoard->Add( docSymGroup );
2870  docSymGroup->SetName( groupName );
2871  GROUP_ID groupID( groupName );
2872  mGroupMap.insert( { groupID, docSymGroup } );
2873 
2874  return groupID;
2875 }
void SetMirrored(bool isMirrored)
Definition: eda_text.h:194
static LSET UserDefinedLayers()
Return a mask with all of the allowable user defined layers.
Definition: lset.cpp:848
void SetDoNotAllowTracks(bool aEnable)
Definition: class_zone.h:738
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:749
void SetHatchGap(int aStep)
Definition: class_zone.h:237
COPPERCODE getCopperCode(const COPPERCODE_ID &aCadstaCopperCodeID)
int getKiCadLength(long long aCadstarLength)
LAYER_ID LayerID
Move all objects in the Symdef to this layer.
bool AddItem(BOARD_ITEM *aItem)
Adds item to group.
int getKiCadHatchCodeGap(const HATCHCODE_ID &aCadstarHatchcodeID)
usual segment : line with rounded ends
void SetEnabledLayers(LSET aMask)
Function SetEnabledLayers changes the bit-mask of enabled layers.
ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:61
virtual void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT)=0
Adds an item to the container.
double GetOrientation() const
Definition: class_module.h:206
std::map< ROUTECODE_ID, ROUTECODE > RouteCodes
void SetBrdLayerId(PCB_LAYER_ID aBrdLayerId)
T NormalizeAngleNeg(T Angle)
Normalize angle to be in the 0.0 .
Definition: trigo.h:256
void SetTypeName(const wxString &aName)
POURING Pouring
Copper pour settings (e.g. relief / hatching /etc.)
PADCODE_ID PadCode
If not empty, override padcode.
#define UNDEFINED_MATERIAL_ID
Inbuilt layer type (cannot be assigned to user layers)
BOARD_STACKUP_ITEM * GetStackupLayer(int aIndex)
int OutlineCount() const
Returns the number of outlines in the set
Inbuilt layer type (cannot be assigned to user layers)
Inbuilt layer type (cannot be assigned to user layers)
bool mDoneNetClassWarning
Used by getKiCadNet() to avoid multiple duplicate warnings.
bool ThermalReliefOnVias
false when subnode "NOVIARELIEF" is present
static const double TXT_HEIGHT_RATIO
CADSTAR fonts are drawn on a 24x24 integer matrix, where the each axis goes from 0 to 24.
NETINFO_ITEM * getKiCadNet(const NET_ID &aCadstarNetID)
Searches mNetMap and returns the NETINFO_ITEM pointer if exists.
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, PCB_LAYER_ID aLayer, int aClearanceValue, int aMaxError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Function TransformShapeWithClearanceToPolygon Convert the pad shape to a closed polygon.
void SetPadConnection(ZONE_CONNECTION aPadConnection)
Definition: class_zone.h:222
std::pair< POINT, POINT > DesignArea
SHAPE_POLY_SET & GetPolyShape()
Definition: pcb_shape.h:243
double getAngleDegrees(const long long &aCadstarAngle)
wxString ReferenceName
This is the name which identifies the symbol in the library Multiple components may exist with the sa...
virtual void SetPosition(const wxPoint &aPos) override
Definition: pcb_text.h:77
long SignalNum
This is undefined if the net has been given a name.
bool mLogLayerWarnings
Used in loadBoardStackup()
this class manage the layers needed to make a physical board they are solder mask,...
void SetPosition(const wxPoint &aPoint) override
Definition: class_track.h:424
std::map< ATTRIBUTE_ID, ATTRNAME > AttributeNames
bool NoVias
From CADSTAR Help: "Check this button to specify that any area created by the Rectangle,...
void Flip(const wxPoint &aCentre, bool aFlipLeftRight) override
Function Flip Flip this object, i.e.
Definition: pcb_text.cpp:156
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
double getAngleTenthDegree(const long long &aCadstarAngle)
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
long ScaleRatioNumerator
Documentation symbols can be arbitrarily scaled when added to a design.
void SetEnd(const wxPoint &aEnd)
Definition: class_track.h:112
void Scale(double aScale)
Definition: pcb_shape.cpp:147
void drawCadstarShape(const SHAPE &aCadstarShape, const PCB_LAYER_ID &aKiCadLayer, const int &aLineThickness, const wxString &aShapeName, BOARD_ITEM_CONTAINER *aContainer, const GROUP_ID &aCadstarGroupID=wxEmptyString, const wxPoint &aMoveVector={ 0, 0 }, const double &aRotationAngle=0.0, const double &aScalingFactor=1.0, const wxPoint &aTransformCentre={ 0, 0 }, const bool &aMirrorInvert=false)
void loadLibraryAreas(const SYMDEF_PCB &aComponent, MODULE *aModule)
LAYER_MAPPING_HANDLER mLayerMappingHandler
Callback to get layer mapping.
std::map< COMP_AREA_ID, COMPONENT_AREA > ComponentAreas
FP_TEXT & Value()
read/write accessors:
Definition: class_module.h:475
void SetTextAngle(double aAngle) override
Definition: pcb_text.cpp:100
PCB_GROUP is a set of BOARD_ITEMs (i.e., without duplicates)
std::map< LINECODE_ID, LINECODE > LineCodes
void loadNetTracks(const NET_ID &aCadstarNetID, const NET_PCB::ROUTE &aCadstarRoute)
virtual void SetStart(const wxPoint &aPoint)
wxString getAttributeValue(const ATTRIBUTE_ID &aCadstarAttributeID, const std::map< ATTRIBUTE_ID, ATTRIBUTE_VALUE > &aCadstarAttributeMap)
ZONE_CONTAINER * getZoneFromCadstarShape(const SHAPE &aCadstarShape, const int &aLineThickness, BOARD_ITEM_CONTAINER *aParentContainer)
void SetTextAngle(double aAngle) override
Definition: fp_text.cpp:68
#define COMPONENT_NAME_2_ATTRID
Component Name 2 Attribute ID - typically used for indicating the placement of designators in placeme...
void SetDoNotAllowFootprints(bool aEnable)
Definition: class_zone.h:740
bool BoxIsolatedPins
true when subnode "BOXPINS" is present
void SetChamferPositions(int aPositions)
has meaning only for chamfered rect pads set the position of the chamfers for orientation 0.
Definition: class_pad.h:522
int mNumNets
Number of nets loaded so far.
bool NoTracks
From CADSTAR Help: "Check this button to specify that any area created by the Rectangle,...
void SetMinIslandArea(long long int aArea)
Definition: class_zone.h:747
Filled closed shape (hatch fill).
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:81
void SetTextPos(const wxPoint &aPoint)
Definition: eda_text.h:253
PCB_GROUP * getKiCadGroup(const GROUP_ID &aCadstarGroupID)
LAYERPAIR getLayerPair(const LAYERPAIR_ID &aCadstarLayerPairID)
void SetVisible(bool aVisible)
Definition: eda_text.h:191
PADS & Pads()
Definition: class_module.h:182
std::map< FIGURE_ID, FIGURE > Figures
#define KEY_COPPER
double GetTextAngle() const
Definition: eda_text.h:180
void SetZoneName(const wxString &aName)
Definition: class_zone.h:114
long ScaleRatioDenominator
Documentation symbols can be arbitrarily scaled when added to a design.
void remapUnsureLayers()
Callback mLayerMappingHandler for layers we aren't sure of.
std::map< GROUP_ID, PCB_GROUP * > mGroupMap
Map between Cadstar and KiCad groups.
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Returns the reference to aHole-th hole in the aIndex-th outline
const wxPoint & GetStart0() const
Definition: fp_shape.h:106
std::map< COPPERCODE_ID, COPPERCODE > CopperCodes
std::map< MATERIAL_ID, MATERIAL > Materials
void SetPosition(const wxPoint &aPos) override
Definition: class_pad.h:166
#define COMPONENT_NAME_ATTRID
Component Name Attribute ID - typically used for placement of designators on silk screen.
wxString Name
Designator e.g. "C1", "R1", etc.
static LSET PTHMask()
layer set for a through hole pad
Definition: class_pad.cpp:138
std::map< LAYER_ID, PCB_LAYER_ID > mLayermap
Map between Cadstar and KiCad Layers.
void SetThermalReliefSpokeWidth(int aThermalReliefSpokeWidth)
Definition: class_zone.h:175
ROUTECODE getRouteCode(const ROUTECODE_ID &aCadstarRouteCodeID)
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
From CADSTAR Help: "Area is for creating areas within which, and nowhere else, certain operations are...
bool HasLocation
Flag to know if this ATTRIBUTE_VALUE has a location i.e.
long MinIsolatedCopper
The value is the length of one side of a notional square.
void SetDrillSize(const wxSize &aSize)
Definition: class_pad.h:240
MODULE * getModuleFromCadstarID(const COMPONENT_ID &aCadstarComponentID)
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
void loadLibraryFigures(const SYMDEF_PCB &aComponent, MODULE *aModule)
ALIGNMENT Alignment
In CADSTAR The default alignment for a TEXT object (when "(No Alignment()" is selected) Bottom Left o...
void checkAndLogHatchCode(const HATCHCODE_ID &aCadstarHatchcodeID)
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:244
virtual void SetLocked(bool aLocked)
Function SetLocked modifies 'lock' status for of the item.
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Returns true if a given subpolygon contains the point aP.
std::map< NET_ID, NETINFO_ITEM * > mNetMap
Map between Cadstar and KiCad Nets.
void NORMALIZE_ANGLE_180(T &Angle)
Definition: trigo.h:374
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
LAYER_ID LayerID
ID on which to draw this [param1].
void Inflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
Performs outline inflation/deflation.
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:85
void loadNetVia(const NET_ID &aCadstarNetID, const NET_PCB::VIA &aCadstarVia)
void SetRoundRectRadiusRatio(double aRadiusScale)
has meaning only for rounded rect pads Set the ratio between the smaller X or Y size and the rounded ...
Definition: class_pad.cpp:236
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
void SetIsRuleArea(bool aEnable)
Definition: class_zone.h:735
bool Routing
From CADSTAR Help: "Area can be used to place routes during Automatic Routing.
wxPoint mDesignCenter
Used for calculating the required offset to apply to the Cadstar design so that it fits in KiCad canv...
void logBoardStackupWarning(const wxString &aCadstarLayerName, const PCB_LAYER_ID &aKiCadLayer)
virtual void Rotate(const wxPoint &aRotCentre, double aAngle) override
Function Rotate Rotate this object.
Definition: pcb_shape.cpp:193
Arcs (with rounded ends)
int PointCount() const
Function PointCount()
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:410
std::map< LAYERPAIR_ID, LAYERPAIR > LayerPairs
Default vias to use between pairs of layers.
Describes an imported layer and how it could be mapped to KiCad Layers.
long Thickness
Note: Units of length are defined in file header.
POINT Origin
Origin of the component (this is used as the reference point when placing the component in the design...
void SetLayer(PCB_LAYER_ID aLayer) override
Function SetLayer sets the layer this item is on.
long MaxPhysicalLayer
Should equal number of copper layers.
std::map< TEMPLATE_ID, TEMPLATE > Templates
A single base class (TRACK) represents both tracks and vias, with subclasses for curved tracks (ARC) ...
wxString Name
This name can be different to the PART name.
ALIGNMENT Alignment
In CADSTAR The default alignment for a TEXT object (when "(No Alignment()" is selected) Bottom Left o...
void Append(int aX, int aY, bool aAllowDuplication=false)
Function Append()
void SetDoNotAllowVias(bool aEnable)
Definition: class_zone.h:737
UNITS Units
Units to display for linear dimensions.
void SetWidth(int aWidth)
Definition: class_track.h:109
const wxString GetReference() const
Function GetReference.
Definition: class_module.h:435
wxString HatchCodeID
Only Applicable for HATCHED Type.
FP_TEXT & Reference()
Definition: class_module.h:476
void loadComponentAttributes(const COMPONENT &aComponent, MODULE *aModule)
From CADSTAR Help: "Area is for creating areas within which, and nowhere else, certain operations are...
long ReliefWidth
if undefined inherits from design
A shape of copper in the component footprint.
std::map< NET_ID, NET_PCB > Nets
Contains tracks and vias.
DIMENSION class definition.
GROUP_ID GroupID
If not empty, this FIGURE is part of a group.
void SetThermalSpokeWidth(int aWidth)
Set the width of the thermal spokes connecting the pad to a zone.
Definition: class_pad.h:475
void drawCadstarText(const TEXT &aCadstarText, BOARD_ITEM_CONTAINER *aContainer, const GROUP_ID &aCadstarGroupID=wxEmptyString, const LAYER_ID &aCadstarLayerOverride=wxEmptyString, const wxPoint &aMoveVector={ 0, 0 }, const double &aRotationAngle=0.0, const double &aScalingFactor=1.0, const wxPoint &aTransformCentre={ 0, 0 }, const bool &aMirrorInvert=false)
virtual void Move(const wxPoint &aMoveVector) override
Function Move move this object.
Definition: pcb_shape.cpp:112
void drawCadstarVerticesAsSegments(const std::vector< VERTEX > &aCadstarVertices, const PCB_LAYER_ID &aKiCadLayer, const int &aLineThickness, BOARD_ITEM_CONTAINER *aContainer, const GROUP_ID &aCadstarGroupID=wxEmptyString, const wxPoint &aMoveVector={ 0, 0 }, const double &aRotationAngle=0.0, const double &aScalingFactor=1.0, const wxPoint &aTransformCentre={ 0, 0 }, const bool &aMirrorInvert=false)
Uses PCB_SHAPE to draw the vertices on mBoard object.
Definition: kiid.h:44
void SetLayerName(const wxString &aName)
void SetClosed(bool aClosed)
Function SetClosed()
void SetLocked(bool aLocked) override
Function SetLocked modifies 'lock' status for of the item.
Definition: class_track.h:141
void SetAnchorPadShape(PAD_SHAPE_T aShape)
Function SetAnchorPadShape Set the shape of the anchor pad for custm shped pads.
Definition: class_pad.h:205
BOARD_STACKUP & GetStackupDescriptor()
PCB_LAYER_ID
A quick note on layer IDs:
void Load(::BOARD *aBoard)
Loads a CADSTAR PCB Archive file into the KiCad BOARD object given.
void SetHatchThickness(int aThickness)
Definition: class_zone.h:234
Inherits from design units (assumed Assignments->Technology->Units)
LSET is a set of PCB_LAYER_IDs.
pads are covered by copper
Represents a point in x,y coordinates.
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:120
PART getPart(const PART_ID &aCadstarPartID)
void SetLayerSet(LSET aLayerSet) override
Definition: class_zone.cpp:242
void SetShape(PCB_SHAPE_TYPE_T aShape)
Definition: pcb_shape.h:113
long ThermalReliefPadsAngle
Orientation for the thermal reliefs. Disabled when !ThermalReliefOnPads (param5)
bool AllowInNoRouting
true when subnode "IGNORETRN" is present
static const wxChar * Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition: lset.cpp:81
HATCHCODE_ID HatchCodeID
Only for FillType = HATCHED.
void SetName(const wxString &aName)
Set the pad name (sometimes called pad number, although it can be an array reference like AA12).
Definition: class_pad.h:131
void SetClearance(int aClearance)
Definition: netclass.h:160
std::vector< LAYER_ID > mPowerPlaneLayers
List of layers that are marked as power plane in CADSTAR.
SHAPE_POLY_SET.
std::map< PART_ID, PART > PartDefinitions
DIMENSION_ID ID
Some ID (doesn't seem to be used) subnode="DIMREF".
constexpr double PCB_IU_PER_MM
void SetPos0(const wxPoint &aPos)
Definition: class_pad.h:224
SHAPE_LINE_CHAIN & Outline(int aIndex)
Returns the reference to aIndex-th outline in the set
bool Placement
From CADSTAR Help: "Auto Placement can place components within this area.
GROUP_ID GroupID
If not empty, this GROUP is part of another GROUP.
long Precision
Number of decimal points to display in the measurement [param3].
void SetDielectricLayerId(int aLayerId)
long Width
Defaults to 0 if using system fonts or, if using CADSTAR font, default to equal height (1:1 aspect ra...
Inbuilt layer type (cannot be assigned to user layers)
Loads a cpa file into a KiCad BOARD object.
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:209
LSET PermittedLayers
KiCad layers that the imported layer can be mapped onto.
LAYER_T
The allowed types of layers, same as Specctra DSN spec.
Definition: class_board.h:62
void Flip(const wxPoint &aCentre, bool aFlipLeftRight) override
Function Flip Flip this object, i.e.
The highest PHYSICAL_LAYER_ID currently defined (i.e.
LSET GetLayerSet() const override
Function GetLayerSet returns a std::bitset of all layers on which the item physically resides.
Definition: class_pad.h:349
SHAPE_LINE_CHAIN getLineChainFromDrawsegments(const std::vector< PCB_SHAPE * > aDrawSegments)
Returns a SHAPE_LINE_CHAIN object from a series of PCB_SHAPE objects.
bool ThermalReliefOnPads
false when subnode "NOPINRELIEF" is present
std::map< SYMDEF_ID, SYMDEF_PCB > ComponentDefinitions
bool mDoneCopperWarning
Used by loadCoppers() to avoid multiple duplicate warnings.
PCB_TEXT & Text()
std::vector< COMPONENT_COPPER > ComponentCoppers
POINT Position
Pad position within the component's coordinate frame.
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Function SetLayer sets the layer this item is on.
Definition: class_zone.cpp:234
void loadLibraryCoppers(const SYMDEF_PCB &aComponent, MODULE *aModule)
void SetSize(const wxSize &aSize)
Definition: class_pad.h:230
void SetRoundRectCornerRadius(double aRadius)
Function SetRoundRectCornerRadius has meaning only for rounded rect pads.
Definition: class_pad.cpp:227
SYMDEF_ID SymdefID
Normally documentation symbols only have TEXT, FIGURE and TEXT_LOCATION objects which are all drawn o...
static LSET AllLayersMask()
Definition: lset.cpp:786
void SetLayerPair(PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer)
Function SetLayerPair For a via m_Layer contains the top layer, the other layer is in m_BottomLayer.
void SetMaterial(const wxString &aName, int aDielectricSubLayer=0)
void SetReference(const wxString &aReference)
Function SetReference.
Definition: class_module.h:445
int getKiCadHatchCodeThickness(const HATCHCODE_ID &aCadstarHatchcodeID)
#define PART_NAME_ATTRID
void SetCenter(const wxPoint &aCenterPoint)
For arcs and circles:
Definition: pcb_shape.h:213
void SetPosition(const wxPoint &aPos) override
void addAttribute(const ATTRIBUTE_LOCATION &aCadstarAttrLoc, const ATTRIBUTE_ID &aCadstarAttributeID, MODULE *aModule, const wxString &aAttributeValue)
Adds a CADSTAR Attribute to a KiCad module.
All physical layers currently defined.
bool AutomaticRepour
true when subnode "REGENERATE" is present
#define KEY_PREPREG
std::set< HATCHCODE_ID > mHatchcodesTested
Used by checkAndLogHatchCode() to avoid multiple duplicate warnings.
void SetDoNotAllowPads(bool aEnable)
Definition: class_zone.h:739
wxString getAttributeName(const ATTRIBUTE_ID &aCadstarAttributeID)
this class manage one layer needed to make a physical board it can be a solder mask,...
int HoleCount(int aOutline) const
Returns the number of holes in a given outline
POINT Origin
Origin of the component (this is used as the reference point when placing the component in the design...
std::map< REUSEBLOCK_ID, REUSEBLOCK > ReuseBlocks
void SetPrecision(int aPrecision)
void AddPolygon(std::vector< wxPoint > &aPolygon)
add a polygon to the zone outline if the zone outline is empty, this is the main outline else it is a...
Definition: class_zone.cpp:814
static const long UNDEFINED_VALUE
void SetAttribute(PAD_ATTR_T aAttribute)
Definition: class_pad.cpp:512
Corresponds to CADSTAR "origin".
void Fracture(POLYGON_MODE aFastMode)
Converts a set of polygons with holes to a singe outline with "slits"/"fractures" connecting the oute...
int AddHole(const SHAPE_LINE_CHAIN &aHole, int aOutline=-1)
Adds a new hole to the given outline (default: last) and returns its index
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
void SetEpsilonR(double aEpsilon, int aDielectricSubLayer=0)
PCB_LAYER_ID GetBrdLayerId() const
void SetPos0(const wxPoint &aPos)
Definition: fp_text.h:169
GROUP_ID GroupID
If not empty, this BOARD is part of a group.
void AddDielectricPrms(int aDielectricPrmsIdx)
true if this stackup item must be taken in account, false to ignore it.
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
void SetThickness(int aThickness, int aDielectricSubLayer=0)
void SetOrientation(double aNewAngle)
void SetLocalClearance(int aClearance)
Definition: class_zone.h:138
bool isModule(BOARD_ITEM_CONTAINER *aContainer)
const KIID m_Uuid
Definition: eda_item.h:151
std::map< SYMDEF_ID, MODULE * > mLibraryMap
Map between Cadstar and KiCad components in the library.
std::map< SPACINGCODE_ID, SPACINGCODE > SpacingCodes
Spacing Design Rules.
wxString GetLayerName() const
PADCODE getPadCode(const PADCODE_ID &aCadstarPadCodeID)
void SetDrillShape(PAD_DRILL_SHAPE_T aShape)
Definition: class_pad.h:342
std::map< INPUT_LAYER_NAME, PCB_LAYER_ID > LAYER_MAP
Map of CADSTAR (INPUT_LAYER_NAME) to KiCad Layers.
std::map< PAD_ID, PADEXCEPTION > PadExceptions
Override pad definitions for this instance.
TEXTCODE getTextCode(const TEXTCODE_ID &aCadstarTextCodeID)
void SetDoNotAllowCopperPour(bool aEnable)
Definition: class_zone.h:736
Use thermal relief for pads.
bool Keepout
From CADSTAR Help: "Auto Placement cannot place components within this area.
int getLineThickness(const LINECODE_ID &aCadstarLineCodeID)
void Move(const wxPoint &aMoveVector) override
Function Move move this object.
Definition: pcb_text.h:82
NETINFO_ITEM handles the data for a net.
Definition: netinfo.h:65
std::vector< CUTOUT > Cutouts
Not Applicable to OPENSHAPE Type.
std::map< TEXTCODE_ID, TEXTCODE > TextCodes
TEMPLATE_ID PouredTemplateID
If not empty, it means this COPPER is part of a poured template.
PCB_SHAPE * getDrawSegmentFromVertex(const POINT &aCadstarStartPoint, const VERTEX &aCadstarVertex, BOARD_ITEM_CONTAINER *aContainer=nullptr, const GROUP_ID &aCadstarGroupID=wxEmptyString, const wxPoint &aMoveVector={ 0, 0 }, const double &aRotationAngle=0.0, const double &aScalingFactor=1.0, const wxPoint &aTransformCentre={ 0, 0 }, const bool &aMirrorInvert=false)
Returns a pointer to a PCB_SHAPE object.
std::map< PHYSICAL_LAYER_ID, LAYER_ID > mCopperLayers
Map of CADSTAR Physical layers to CADSTAR Layer IDs.
void SetHatchOrientation(double aStep)
Definition: class_zone.h:240
void SetNet(NETINFO_ITEM *aNetInfo)
Function SetNet Sets a NET_INFO object for the item.
void SetFillMode(ZONE_FILL_MODE aFillMode)
Definition: class_zone.h:162
void RemoveAll()
Delete all items in list and clear the list.
Inbuilt layer type (cannot be assigned to user layers)
std::map< DIMENSION_ID, DIMENSION > Dimensions
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:201
bool NoTracks
From CADSTAR Help: "Area cannot be used to place routes during automatic routing.
void SetStart(const wxPoint &aStart)
Definition: pcb_shape.h:132
wxString Name
This is undefined (wxEmptyString) if the net is unnamed.
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:208
polygon (not yet used for tracks, but could be in microwave apps)
wxString Name
Imported layer name as displayed in original application.
#define _(s)
Definition: 3d_actions.cpp:33
GROUP_ID createUniqueGroupID(const wxString &aName)
Adds a new PCB_GROUP* to mGroupMap.
SHAPE_LINE_CHAIN.
std::set< PADCODE_ID > mPadcodesTested
Used by getKiCadPad() to avoid multiple duplicate warnings.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
T NormalizeAnglePos(T Angle)
Normalize angle to be in the 0.0 .
Definition: trigo.h:268
PCB_LAYER_ID getKiCadLayer(const LAYER_ID &aCadstarLayerID)
std::map< HATCHCODE_ID, HATCHCODE > HatchCodes
void addToGroup(const GROUP_ID &aCadstarGroupID, BOARD_ITEM *aKiCadItem)
long SliverWidth
Minimum width of copper that may be created.
void drawCadstarCutoutsAsSegments(const std::vector< CUTOUT > &aCutouts, const PCB_LAYER_ID &aKiCadLayer, const int &aLineThickness, BOARD_ITEM_CONTAINER *aContainer, const GROUP_ID &aCadstarGroupID=wxEmptyString, const wxPoint &aMoveVector={ 0, 0 }, const double &aRotationAngle=0.0, const double &aScalingFactor=1.0, const wxPoint &aTransformCentre={ 0, 0 }, const bool &aMirrorInvert=false)
Uses PCB_SHAPE to draw the cutouts on mBoard object.
double GetAngle() const
Definition: pcb_shape.h:108
Plated through hole pad.
Definition: pad_shapes.h:80
void SetDrill(int aDrill)
Function SetDrill sets the drill value for vias.
Definition: class_track.h:486
NETCLASS * GetDefault() const
Function GetDefault.
void SetValue(const wxString &aValue)
Function SetValue.
Definition: class_module.h:469
D_PAD * getKiCadPad(const PAD &aCadstarPad, MODULE *aParent)
const wxPoint & GetEnd0() const
Definition: fp_shape.h:109
void SetWidth(int aWidth)
Definition: pcb_shape.h:99
BOARD_STACKUP_ITEM_TYPE
Unfilled open shape. Cannot have cutouts.
Definition: eserie.h:43
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:68
void SetClass(const NETCLASSPTR &aNetClass)
Function SetClass sets aNetclass into this NET.
long ReliefClearance
if undefined inherits from design
PHYSICAL_LAYER_ID PhysicalLayer
If UNDEFINED, no physical layer is assigned (e.g.
void SetShape(PAD_SHAPE_T aShape)
Set the new shape of this pad.
Definition: class_pad.h:155
wxString Alternate
This is in addition to ReferenceName.
COPPERCODE_ID ReliefCopperCodeID
From CADSTAR Help: "Relief Copper Code is for selecting the width of line used to draw the thermal re...
void SetOrientation(double aAngle)
Function SetOrientation sets the rotation angle of the pad.
Definition: class_pad.cpp:531
std::map< COMPONENT_ID, MODULE * > mComponentMap
Map between Cadstar and KiCad components on the board.
std::map< DOCUMENTATION_SYMBOL_ID, DOCUMENTATION_SYMBOL > DocumentationSymbols
static LSET AllBoardTechMask()
Return a mask holding board technical layers (no CU layer) on both side.
Definition: lset.cpp:826
Inbuilt layer type (cannot be assigned to user layers)
void SetStart(const wxPoint &aStart)
Definition: class_track.h:115
long MinDisjointCopper
The value is the length of one side of a notional square.
void SetChamferRectRatio(double aChamferScale)
has meaning only for chamfered rect pads Set the ratio between the smaller X or Y size and chamfered ...
Definition: class_pad.cpp:244
PCB_LAYER_ID AutoMapLayer
Best guess as to what the equivalent KiCad layer might be.
std::map< ROUTECODE_ID, NETCLASSPTR > mNetClassMap
Map between Cadstar and KiCad classes.
virtual void Flip(const wxPoint &aCentre, bool aFlipLeftRight) override
Function Flip Flip this object, i.e.
Definition: pcb_shape.cpp:248
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.h:164
void SetPolyShape(const SHAPE_POLY_SET &aShape)
Definition: pcb_shape.h:251
wxString LAYER_ID
ID of a Sheet (if schematic) or board Layer (if PCB)
PCB_LAYER_ID getKiCadCopperLayerID(unsigned int aLayerNum)
long ClearanceWidth
Specifies the space around pads when pouring (i.e.
wxPoint GetPosition() const override
Definition: class_module.h:201
bool isLayerSet(const LAYER_ID &aCadstarLayerID)
double ArcTangente(int dy, int dx)
Definition: trigo.cpp:162
long ThermalReliefViasAngle
Disabled when !ThermalReliefOnVias (param6)
Abstract interface for BOARD_ITEMs capable of storing other items inside.
long MinRouteWidth
Manufacturing Design Rule. Corresponds to "Thin Route Width".
std::vector< PCB_SHAPE * > getDrawSegmentsFromVertices(const std::vector< VERTEX > &aCadstarVertices, BOARD_ITEM_CONTAINER *aContainer=nullptr, const GROUP_ID &aCadstarGroupID=wxEmptyString, const wxPoint &aMoveVector={ 0, 0 }, const double &aRotationAngle=0.0, const double &aScalingFactor=1.0, const wxPoint &aTransformCentre={ 0, 0 }, const bool &aMirrorInvert=false)
Returns a vector of pointers to PCB_SHAPE objects.
void AddPrimitive(PCB_SHAPE *aPrimitive)
Add item to the custom shape primitives list.
std::map< COMPONENT_ID, COMPONENT > Components
Templates are CADSTAR's equivalent to a "filled zone".
void Add(BOARD_STACKUP_ITEM *aItem)
Add a new item in stackup layer.
bool NoVias
From CADSTAR Help: "No vias will be placed within this area by the automatic router.
static LSET UserMask()
Definition: lset.cpp:833
double getHatchCodeAngleDegrees(const HATCHCODE_ID &aCadstarHatchcodeID)
std::map< ATTRIBUTE_ID, ATTRIBUTE_VALUE > AttributeValues
int Parse(const UTF8 &aId, LIB_ID_TYPE aType, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:122
For better understanding of the points that make a dimension:
HATCHCODE getHatchCode(const HATCHCODE_ID &aCadstarHatchcodeID)
std::vector< TRACK * > makeTracksFromDrawsegments(const std::vector< PCB_SHAPE * > aDrawsegments, BOARD_ITEM_CONTAINER *aParentContainer, NETINFO_ITEM *aNet=nullptr, PCB_LAYER_ID aLayerOverride=PCB_LAYER_ID::UNDEFINED_LAYER, int aWidthOverride=-1)
Returns a vector of pointers to TRACK/ARC objects.
VIACODE getViaCode(const VIACODE_ID &aCadstarViaCodeID)
void SetOffset(const wxPoint &aOffset)
Definition: class_pad.h:247
virtual void SetAngle(double aAngle, bool aUpdateEnd=true)
Function SetAngle sets the angle for arcs, and normalizes it within the range 0 - 360 degrees.
Definition: pcb_shape.cpp:435
void SetViaType(VIATYPE aViaType)
Definition: class_track.h:385
long AdditionalIsolation
This is the gap to apply in routes and pads in addition to the existing pad-to-copper or route-to-cop...
#define _HKI(x)
void loadLibraryPads(const SYMDEF_PCB &aComponent, MODULE *aModule)
void SetThermalGap(int aGap)
Definition: class_pad.h:483
NO_ALIGNMENT has different meaning depending on the object type.
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
void SetLossTangent(double aTg, int aDielectricSubLayer=0)
std::map< ATTRIBUTE_ID, TEXT_LOCATION > TextLocations
This contains location of any attributes, including designator position.
Filled closed shape (solid fill).
void SetFPID(const LIB_ID &aFPID)
Definition: class_module.h:211
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:133
LSET getKiCadLayerSet(const LAYER_ID &aCadstarLayerID)
void SetLayerSet(LSET aLayers) override
Definition: class_pad.h:348
bool mDoneSpacingClassWarning
Used by getKiCadNet() to avoid multiple duplicate warnings.
SHAPE_POLY_SET getPolySetFromCadstarShape(const SHAPE &aCadstarShape, const int &aLineThickness=-1, BOARD_ITEM_CONTAINER *aContainer=nullptr, const wxPoint &aMoveVector={ 0, 0 }, const double &aRotationAngle=0.0, const double &aScalingFactor=1.0, const wxPoint &aTransformCentre={ 0, 0 }, const bool &aMirrorInvert=false)
Returns a SHAPE_POLY_SET object from a Cadstar SHAPE.
void SetThermalReliefGap(int aThermalReliefGap)
Definition: class_zone.h:165
std::map< BOARD_ID, BOARD > Boards
Normally CADSTAR only allows one board but implemented this as a map just in case.
void SetHatchStyle(ZONE_BORDER_DISPLAY_STYLE aStyle)
Definition: class_zone.h:595
virtual void SetEnd(const wxPoint &aPoint)
void logBoardStackupMessage(const wxString &aCadstarLayerName, const PCB_LAYER_ID &aKiCadLayer)
void SetEnd(const wxPoint &aEnd)
Definition: pcb_shape.h:143
void SetUnits(EDA_UNITS aUnits)
wxPoint getKiCadPoint(wxPoint aCadstarPoint)
Scales, offsets and inverts y axis to make the point usable directly in KiCad.
void SetArcStart(const wxPoint &aArcStartPoint)
Initialize the start arc point.
Definition: pcb_shape.h:197
int KiCadUnitMultiplier
Use this value to convert units in this CPA file to KiCad units.
Represents a cutout in a closed shape (e.g.
Linear, leader (radius/diameter) or angular dimension.
void SetName(wxString aName)
wxString Identifier
This is an identifier that is displayed to the user.
BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
Represents a vertex in a shape.
POINT Origin
Origin of the component (this is used as the reference point when placing the component in the design...
void SetDescription(const wxString &aDoc)
Definition: class_module.h:214