KiCad PCB EDA Suite
Loading...
Searching...
No Matches
cadstar_sch_archive_loader.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2020-2021 Roberto Fernandez Bautista <[email protected]>
5 * Copyright (C) 2020-2023 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
28
29#include <bus_alias.h>
30#include <core/mirror.h>
31#include <core/kicad_algo.h>
32#include <eda_text.h>
33#include <macros.h>
34#include <progress_reporter.h>
35#include <string_utils.h>
36#include <sch_bus_entry.h>
37#include <sch_edit_frame.h> //SYMBOL_ORIENTATION_T
38#include <sch_io/sch_io_mgr.h>
39#include <sch_junction.h>
40#include <sch_line.h>
41#include <sch_screen.h>
42#include <sch_shape.h>
43#include <sch_sheet.h>
44#include <sch_sheet_path.h>
45#include <sch_sheet_pin.h>
46#include <sch_label.h>
47#include <schematic.h>
48#include <sim/sim_model.h>
49#include <trigo.h>
51
52
53const wxString PartNameFieldName = "Part Name";
54const wxString PartNumberFieldName = "Part Number";
55const wxString PartVersionFieldName = "Part Version";
56const wxString PartAcceptanceFieldName = "Part Acceptance";
57
58
59wxString CADSTAR_SCH_ARCHIVE_LOADER::CreateLibName( const wxFileName& aFileName,
60 const SCH_SHEET* aRootSheet )
61{
62 wxString libName = aFileName.GetName();
63
64 if( libName.IsEmpty() && aRootSheet )
65 {
66 wxFileName fn( aRootSheet->GetFileName() );
67 libName = fn.GetName();
68 }
69
70 if( libName.IsEmpty() )
71 libName = "noname";
72
73 libName = LIB_ID::FixIllegalChars( libName, true ).wx_str();
74
75 return libName;
76}
77
78
79std::vector<LIB_SYMBOL*> CADSTAR_SCH_ARCHIVE_LOADER::LoadPartsLib( const wxString& aFilename )
80{
82 m_progressReporter->SetNumPhases( 3 ); // (0) Read csa, (1) Parse csa, (3) Load lib
83
84 Parse();
85
87
88 if( !p.CheckFileHeader( aFilename.utf8_string() ) )
89 THROW_IO_ERROR( _( "File does not appear to be a CADSTAR parts Library file" ) );
90
91 // TODO: we could add progress reporting for reading .lib
92 CADSTAR_PARTS_LIB_MODEL csLib = p.ReadFile( aFilename.utf8_string() );
93
95 {
97 long numSteps = csLib.m_PartEntries.size();
99 }
100
101 std::vector<LIB_SYMBOL*> retVal;
102
103 for( const CADSTAR_PART_ENTRY& part : csLib.m_PartEntries )
104 {
105 std::unique_ptr<LIB_SYMBOL> loadedPart = loadLibPart( part );
106
107 checkPoint();
108
109 if( loadedPart )
110 retVal.push_back( loadedPart.release() );
111 }
112
113 return retVal;
114}
115
116
117std::unique_ptr<LIB_SYMBOL>
119{
120 wxString escapedPartName = EscapeString( aPart.m_Name, CTX_LIBID );
121 std::unique_ptr<LIB_SYMBOL> retSym;
122
123 int unit = 0;
124
125 for( const CADSTAR_PART_SYMBOL_ENTRY& sym : aPart.m_Symbols )
126 {
127 ++unit;
128 wxString alternateName = sym.m_SymbolAlternateName.value_or( "" );
129 SYMDEF_ID symbolID = getSymDefFromName( sym.m_SymbolName, alternateName );
130
131 if( !Library.SymbolDefinitions.count( symbolID ) )
132 {
133 m_reporter->Report( wxString::Format( _( "Unable to find symbol %s, referenced by part "
134 "%s. The part was not loaded." ),
135 generateLibName( sym.m_SymbolName, alternateName ),
136 aPart.m_Name ),
138
139 return nullptr;
140 }
141
142 // Load the graphical symbol for this gate
143 std::unique_ptr<LIB_SYMBOL> kiSymDef( loadSymdef( symbolID )->Duplicate() );
144
145 if( (int)sym.m_Pins.size() != kiSymDef->GetPinCount() )
146 {
147 m_reporter->Report( wxString::Format( _( "Inconsistent pin numbers in symbol %s "
148 "compared to the one defined in part %s. The "
149 "part was not loaded." ),
150 generateLibName( sym.m_SymbolName, alternateName ),
151 aPart.m_Name ),
153
154 return nullptr;
155 }
156
157 wxASSERT( m_symDefTerminalsMap.count( symbolID ) ); //loadSymDef should have populated this
158
159
160 // Update the pin numbers to match those defined in the Cadstar part
161 for( auto& [storedPinNum, termID] : m_symDefTerminalsMap[symbolID] )
162 {
163 wxCHECK( termID > 0 && sym.m_Pins.size() >= size_t( termID ), nullptr );
164 SCH_PIN* pin = kiSymDef->GetPin( storedPinNum );
165 size_t termIdx = size_t( termID ) - 1;
166
167 // For now leave numerical pin number. Otherwise, when loading the
168 // .cpa file we won't be able to link up to the footprint pads, but if
169 // we solve this, we could then load alphanumeric pin numbers as below:
170 //
171 // if( aPart.m_PinNamesMap.count( termID ) )
172 // partPinNum = wxString( aPart.m_PinNamesMap.at( termID ) );
173 //
174 wxString partPinNum = wxString::Format( "%ld", sym.m_Pins[termIdx].m_Identifier );
175 pin->SetNumber( partPinNum );
176
177 if( aPart.m_PinNamesMap.count( termID ) )
178 pin->SetName( HandleTextOverbar( aPart.m_PinNamesMap.at( termID ) ) );
179 else if( aPart.m_PinLabelsMap.count( termID ) )
180 pin->SetName( HandleTextOverbar( aPart.m_PinLabelsMap.at( termID ) ) );
181
182 pin->SetType( getKiCadPinType( sym.m_Pins[termIdx].m_Type ) );
183
184 // @todo: Load pin/gate swapping information once kicad supports this
185 }
186
187 if( unit == 1 )
188 {
189 wxCHECK( kiSymDef->GetUnitCount() == 1, nullptr );
190 // The first unit can just be moved to the part symbol
191 retSym = std::move( kiSymDef );
192
193 retSym->SetUnitCount( aPart.m_Symbols.size(), true );
194
195 retSym->SetName( escapedPartName );
196 retSym->GetReferenceField().SetText( aPart.m_ComponentStem );
197 retSym->GetValueField().SetText( aPart.m_Value.value_or( "" ) );
199 retSym->SetDescription( aPart.m_Description.value_or( "" ) );
200
201 auto addFieldIfHasValue =
202 [&]( const wxString& name, const std::optional<std::string>& value )
203 {
204 if( value.has_value() )
205 addNewFieldToSymbol( name, retSym )->SetText( value.value() );
206 };
207
208 addFieldIfHasValue( PartNumberFieldName, aPart.m_Number );
209 addFieldIfHasValue( PartVersionFieldName, aPart.m_Version );
210 addFieldIfHasValue( PartAcceptanceFieldName, aPart.m_AcceptancePartName );
211
213 aPart.m_Pcb_alternate.value_or( "" ) );
214
215 if( aPart.m_SpiceModel.has_value() )
216 {
217 wxString modelVal = wxString::Format( "model=\"%s\"", aPart.m_SpiceModel.value() );
218 addNewFieldToSymbol( SIM_DEVICE_FIELD, retSym )->SetText( "SPICE" );
219 addNewFieldToSymbol( SIM_PARAMS_FIELD, retSym )->SetText( modelVal );
220 }
221
222 // Load all part attributes, regardless of original cadstar type, to the symbol
223
224 // @todo some cadstar part attributes have a "read-only" flag. We should load this
225 // when KiCad supports read-only fields.
226
227 for( auto& [fieldName, value] : aPart.m_UserAttributes )
228 addNewFieldToSymbol( fieldName, retSym )->SetText( value );
229
230 for( auto& [fieldName, attrValue] : aPart.m_SchAttributes )
231 addNewFieldToSymbol( fieldName, retSym )->SetText( attrValue.m_Value );
232
233 for( auto& [fieldName, attrValue] : aPart.m_PcbAttributes )
234 addNewFieldToSymbol( fieldName, retSym )->SetText( attrValue.m_Value );
235
236 for( auto& [fieldName, attrValue] : aPart.m_SchAndPcbAttributes )
237 addNewFieldToSymbol( fieldName, retSym )->SetText( attrValue.m_Value );
238
239 for( auto& [fieldName, attrValue] : aPart.m_PartAttributes )
240 addNewFieldToSymbol( fieldName, retSym )->SetText( attrValue.m_Value );
241
242 // Load all hidden pins onto the first unit of the symbol in KiCad
243 // We load them in a spiral sequence, starting at the center of the symbol BBOX
244 VECTOR2I symCenter = retSym->GetBodyBoundingBox( unit, 0, false, false ).GetCenter();
245 symCenter.y = -symCenter.y; // need to invert the y coord for lib symbols.
246
247 VECTOR2I delta( 0, 1 );
248 VECTOR2I direction( 0, -1 );
249 int spacing = schIUScale.MilsToIU( 50 ); // for now, place on a 50mil grid
250
251 for( auto& [signalName, csPinVector] : aPart.m_HiddenPins )
252 {
253 for( const CADSTAR_PART_PIN& csPin : csPinVector )
254 {
255 std::unique_ptr<SCH_PIN> pin = std::make_unique<SCH_PIN>( retSym.get() );
256
257 long pinNum = csPin.m_Identifier;
258 pin->SetNumber( wxString::Format( "%ld", pinNum ) );
259 pin->SetName( signalName );
260 pin->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
261
262 pin->SetVisible( false );
263
264 // Generate the coordinate for the pin. We don't want overlapping pins
265 // and ideally close to the center of the symbol, so we load pins in a
266 // spiral sequence around the center
267 if( delta.x == delta.y
268 || ( delta.x < 0 && delta.x == -delta.y )
269 || ( delta.x > 0 && delta.x == 1 - delta.y ) )
270 {
271 // change direction
272 direction = { -direction.y, direction.x };
273 }
274
275 delta += direction;
276 VECTOR2I offset = delta * spacing;
277 pin->SetPosition( symCenter + offset );
278 pin->SetLength( 0 ); //CADSTAR Pins are just a point (have no length)
279 pin->SetShape( GRAPHIC_PINSHAPE::LINE );
280 pin->SetUnit( unit );
281 retSym->AddDrawItem( pin.release() );
282 }
283 }
284 }
285 else
286 { // Source: Dest:
287 copySymbolItems( kiSymDef, retSym, unit, false /* aOverrideFields */ );
288 }
289
290
291 retSym->SetShowPinNames( aPart.m_PinsVisible );
292 retSym->SetShowPinNumbers( aPart.m_PinsVisible );
293 }
294
295
296 return retSym;
297}
298
299
300void CADSTAR_SCH_ARCHIVE_LOADER::copySymbolItems( std::unique_ptr<LIB_SYMBOL>& aSourceSym,
301 std::unique_ptr<LIB_SYMBOL>& aDestSym,
302 int aDestUnit, bool aOverrideFields )
303{
304 // Ensure there are no items on the unit we want to load onto
305 for( SCH_ITEM* item : aDestSym->GetUnitDrawItems( aDestUnit, 0 /*aConvert*/ ) )
306 aDestSym->RemoveDrawItem( item );
307
308 // Copy all draw items
309 for( SCH_ITEM* newItem : aSourceSym->GetUnitDrawItems( 1, 0 /*aConvert*/ ) )
310 {
311 SCH_ITEM* itemCopy = static_cast<SCH_ITEM*>( newItem->Clone() );
312 itemCopy->SetParent( aDestSym.get() );
313 itemCopy->SetUnit( aDestUnit );
314 aDestSym->AddDrawItem( itemCopy );
315 }
316
317 //Copy / override all fields
318 if( aOverrideFields )
319 {
320 std::vector<SCH_FIELD*> fieldsToCopy;
321 aSourceSym->GetFields( fieldsToCopy );
322
323 for( SCH_FIELD* templateField : fieldsToCopy )
324 {
325 SCH_FIELD* appliedField = addNewFieldToSymbol( templateField->GetName(), aDestSym );
326 templateField->Copy( appliedField );
327 }
328 }
329}
330
331
333{
334 wxCHECK( aSchematic, /* void */ );
335
337 m_progressReporter->SetNumPhases( 3 ); // (0) Read file, (1) Parse file, (2) Load file
338
339 Parse();
340
341 checkDesignLimits(); // Throws if error found
342
343 // Assume the center at 0,0 since we are going to be translating the design afterwards anyway
344 m_designCenter = { 0, 0 };
345
346 m_schematic = aSchematic;
347 m_rootSheet = aRootSheet;
348
350 {
352 long numSteps = 11; // one step for each of below functions + one at the end of import
353
354 // Step 4 is by far the longest - add granularity in reporting
355 numSteps += Parts.PartDefinitions.size();
356
358 }
359
360 loadTextVariables(); // Load text variables right at the start to ensure bounding box
361 // calculations work correctly for text items
362 checkPoint(); // Step 1
363 loadSheets();
364 checkPoint(); // Step 2
366 checkPoint(); // Step 3
368 checkPoint(); // Step 4, Subdivided into extra steps
370 checkPoint(); // Step 5
371 loadBusses();
372 checkPoint(); // Step 6
373 loadNets();
374 checkPoint(); // Step 7
375 loadFigures();
376 checkPoint(); // Step 8
377 loadTexts();
378 checkPoint(); // Step 9
380 checkPoint(); // Step 10
381
382 if( Schematic.VariantHierarchy.Variants.size() > 0 )
383 {
384 m_reporter->Report( wxString::Format( _( "The CADSTAR design contains variants which has "
385 "no KiCad equivalent. Only the master variant "
386 "('%s') was loaded." ),
387 Schematic.VariantHierarchy.Variants.at( "V0" ).Name ),
389 }
390
391 if( Schematic.Groups.size() > 0 )
392 {
393 m_reporter->Report( _( "The CADSTAR design contains grouped items which has no KiCad "
394 "equivalent. Any grouped items have been ungrouped." ),
396 }
397
398 if( Schematic.ReuseBlocks.size() > 0 )
399 {
400 m_reporter->Report( _( "The CADSTAR design contains re-use blocks which has no KiCad "
401 "equivalent. The re-use block information has been discarded during "
402 "the import." ),
404 }
405
406
407 // For all sheets, center all elements and re calculate the page size:
408 for( std::pair<LAYER_ID, SCH_SHEET*> sheetPair : m_sheetMap )
409 {
410 SCH_SHEET* sheet = sheetPair.second;
411
412 // Calculate the new sheet size.
413 BOX2I sheetBoundingBox;
414
415 for( SCH_ITEM* item : sheet->GetScreen()->Items() )
416 {
417 BOX2I bbox;
418
419 // Only use the visible fields of the symbols to calculate their bounding box
420 // (hidden fields could be very long and artificially enlarge the sheet bounding box)
421 if( item->Type() == SCH_SYMBOL_T )
422 {
423 SCH_SYMBOL* comp = static_cast<SCH_SYMBOL*>( item );
424 bbox = comp->GetBodyAndPinsBoundingBox();
425
426 for( const SCH_FIELD& field : comp->GetFields() )
427 {
428 if( field.IsVisible() )
429 bbox.Merge( field.GetBoundingBox() );
430 }
431 }
432 else if( item->Type() == SCH_TEXT_T )
433 {
434 SCH_TEXT* txtItem = static_cast<SCH_TEXT*>( item );
435 wxString txt = txtItem->GetText();
436
437 if( txt.Contains( "${" ) )
438 continue; // We can't calculate bounding box of text items with variables
439 else
440 bbox = txtItem->GetBoundingBox();
441 }
442 else
443 {
444 bbox = item->GetBoundingBox();
445 }
446
447 sheetBoundingBox.Merge( bbox );
448 }
449
450 // Find the screen grid of the original CADSTAR design
452
457
459
460 auto roundToNearestGrid =
461 [&]( int aNumber ) -> int
462 {
463 int error = aNumber % grid;
464 int absError = sign( error ) * error;
465
466 if( absError > ( grid / 2 ) )
467 return aNumber + ( sign( error ) * grid ) - error;
468 else
469 return aNumber - error;
470 };
471
472 // When exporting to pdf, CADSTAR applies a margin of 3% of the longest dimension (height
473 // or width) to all 4 sides (top, bottom, left right). For the import, we are also rounding
474 // the margin to the nearest grid, ensuring all items remain on the grid.
475 VECTOR2I targetSheetSize = sheetBoundingBox.GetSize();
476 int longestSide = std::max( targetSheetSize.x, targetSheetSize.y );
477 int margin = ( (double) longestSide * 0.03 );
478 margin = roundToNearestGrid( margin );
479 targetSheetSize += margin * 2;
480
481 // Update page size always
482 PAGE_INFO pageInfo = sheet->GetScreen()->GetPageSettings();
483 pageInfo.SetWidthMils( schIUScale.IUToMils( targetSheetSize.x ) );
484 pageInfo.SetHeightMils( schIUScale.IUToMils( targetSheetSize.y ) );
485
486 // Set the new sheet size.
487 sheet->GetScreen()->SetPageSettings( pageInfo );
488
490 VECTOR2I sheetcentre( pageSizeIU.x / 2, pageSizeIU.y / 2 );
491 VECTOR2I itemsCentre = sheetBoundingBox.Centre();
492
493 // round the translation to nearest point on the grid
494 VECTOR2I translation = sheetcentre - itemsCentre;
495 translation.x = roundToNearestGrid( translation.x );
496 translation.y = roundToNearestGrid( translation.y );
497
498 // Translate the items.
499 std::vector<SCH_ITEM*> allItems;
500
501 std::copy( sheet->GetScreen()->Items().begin(), sheet->GetScreen()->Items().end(),
502 std::back_inserter( allItems ) );
503
504 for( SCH_ITEM* item : allItems )
505 {
506 item->Move( translation );
507 item->ClearFlags();
508 sheet->GetScreen()->Update( item );
509 }
510 }
511
512 checkPoint();
513
514 m_reporter->Report( _( "CADSTAR fonts are different to the ones in KiCad. This will likely "
515 "result in alignment issues. Please review the imported text elements "
516 "carefully and correct manually if required." ),
518
519 m_reporter->Report( _( "The CADSTAR design has been imported successfully.\n"
520 "Please review the import errors and warnings (if any)." ) );
521}
522
523
525{
527
528 //Note: can't use getKiCadPoint() due VECTOR2I being int - need long long to make the check
529 long long designSizeXkicad = (long long) designLimit.x / KiCadUnitDivider;
530 long long designSizeYkicad = (long long) designLimit.y / KiCadUnitDivider;
531
532 // Max size limited by the positive dimension of VECTOR2I (which is an int)
533 constexpr long long maxDesignSizekicad = std::numeric_limits<int>::max();
534
535 if( designSizeXkicad > maxDesignSizekicad || designSizeYkicad > maxDesignSizekicad )
536 {
537 THROW_IO_ERROR( wxString::Format(
538 _( "The design is too large and cannot be imported into KiCad. \n"
539 "Please reduce the maximum design size in CADSTAR by navigating to: \n"
540 "Design Tab -> Properties -> Design Options -> Maximum Design Size. \n"
541 "Current Design size: %.2f, %.2f millimeters. \n"
542 "Maximum permitted design size: %.2f, %.2f millimeters.\n" ),
543 (double) designSizeXkicad / SCH_IU_PER_MM,
544 (double) designSizeYkicad / SCH_IU_PER_MM,
545 (double) maxDesignSizekicad / SCH_IU_PER_MM,
546 (double) maxDesignSizekicad / SCH_IU_PER_MM ) );
547 }
548}
549
550
552{
553 const std::vector<LAYER_ID>& orphanSheets = findOrphanSheets();
554 SCH_SHEET_PATH rootPath;
555 rootPath.push_back( m_rootSheet );
556 rootPath.SetPageNumber( wxT( "1" ) );
557
558 if( orphanSheets.size() > 1 )
559 {
560 int x = 1;
561 int y = 1;
562
563 for( LAYER_ID sheetID : orphanSheets )
564 {
565 VECTOR2I pos( x * schIUScale.MilsToIU( 1000 ), y * schIUScale.MilsToIU( 1000 ) );
566 VECTOR2I siz( schIUScale.MilsToIU( 1000 ), schIUScale.MilsToIU( 1000 ) );
567
568 loadSheetAndChildSheets( sheetID, pos, siz, rootPath );
569
570 x += 2;
571
572 if( x > 10 ) // start next row
573 {
574 x = 1;
575 y += 2;
576 }
577 }
578 }
579 else if( orphanSheets.size() > 0 )
580 {
581 LAYER_ID rootSheetID = orphanSheets.at( 0 );
582
583 wxFileName loadedFilePath = wxFileName( Filename );
584
585 std::string filename = wxString::Format( "%s_%02d", loadedFilePath.GetName(),
586 getSheetNumber( rootSheetID ) )
587 .ToStdString();
588 ReplaceIllegalFileNameChars( &filename );
589 filename += wxT( "." ) + wxString( FILEEXT::KiCadSchematicFileExtension );
590
591 wxFileName fn( m_schematic->Prj().GetProjectPath() + filename );
592 m_rootSheet->GetScreen()->SetFileName( fn.GetFullPath() );
593
594 m_sheetMap.insert( { rootSheetID, m_rootSheet } );
595 loadChildSheets( rootSheetID, rootPath );
596 }
597 else if( Header.Format.Type == "SYMBOL" )
598 {
599 THROW_IO_ERROR( _( "The selected file is a CADSTAR symbol library. It does not contain a "
600 "schematic design so cannot be imported/opened in this way." ) );
601 }
602 else
603 {
604 THROW_IO_ERROR( _( "The CADSTAR schematic might be corrupt: there is no root sheet." ) );
605 }
606}
607
608
610{
611 for( std::pair<BLOCK_ID, BLOCK> blockPair : Schematic.Blocks )
612 {
613 BLOCK& block = blockPair.second;
614 LAYER_ID sheetID = "";
615
616 if( block.Type == BLOCK::TYPE::PARENT )
617 sheetID = block.LayerID;
618 else if( block.Type == BLOCK::TYPE::CHILD )
619 sheetID = block.AssocLayerID;
620 else
621 continue;
622
623 if( m_sheetMap.find( sheetID ) != m_sheetMap.end() )
624 {
625 SCH_SHEET* sheet = m_sheetMap.at( sheetID );
626
627 for( std::pair<TERMINAL_ID, TERMINAL> termPair : block.Terminals )
628 {
629 TERMINAL term = termPair.second;
630 wxString name = "YOU SHOULDN'T SEE THIS TEXT. THIS IS A BUG.";
631
632 SCH_HIERLABEL* sheetPin = nullptr;
633
634 if( block.Type == BLOCK::TYPE::PARENT )
635 sheetPin = new SCH_HIERLABEL();
636 else if( block.Type == BLOCK::TYPE::CHILD )
637 sheetPin = new SCH_SHEET_PIN( sheet );
638
639 sheetPin->SetText( name );
640 sheetPin->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED );
641 sheetPin->SetSpinStyle( getSpinStyle( term.OrientAngle, false ) );
642 sheetPin->SetPosition( getKiCadPoint( term.Position ) );
643
644 if( sheetPin->Type() == SCH_SHEET_PIN_T )
645 sheet->AddPin( (SCH_SHEET_PIN*) sheetPin );
646 else
647 sheet->GetScreen()->Append( sheetPin );
648
649 BLOCK_PIN_ID blockPinID = std::make_pair( block.ID, term.ID );
650 m_sheetPinMap.insert( { blockPinID, sheetPin } );
651 }
652 }
653 }
654}
655
656
658{
659 for( std::pair<PART_ID, PART> partPair : Parts.PartDefinitions )
660 {
661 PART_ID partID = partPair.first;
662 PART part = partPair.second;
663
664 wxString escapedPartName = EscapeString( part.Name, CTX_LIBID );
665 LIB_SYMBOL* kiSym = new LIB_SYMBOL( escapedPartName );
666
667 kiSym->SetUnitCount( part.Definition.GateSymbols.size() );
668 bool ok = true;
669
670 for( std::pair<GATE_ID, PART::DEFINITION::GATE> gatePair : part.Definition.GateSymbols )
671 {
672 GATE_ID gateID = gatePair.first;
673 PART::DEFINITION::GATE gate = gatePair.second;
674 SYMDEF_ID symbolID = getSymDefFromName( gate.Name, gate.Alternate );
675
676 if( symbolID.IsEmpty() )
677 {
678 m_reporter->Report( wxString::Format( _( "Part definition '%s' references symbol "
679 "'%s' (alternate '%s') which could not be "
680 "found in the symbol library. The part has "
681 "not been loaded into the KiCad library." ),
682 part.Name,
683 gate.Name,
684 gate.Alternate ),
686
687 ok = false;
688 break;
689 }
690
691 m_partSymbolsMap.insert( { { partID, gateID }, symbolID } );
692 loadSymbolGateAndPartFields( symbolID, part, gateID, kiSym );
693 }
694
695 if( ok && part.Definition.GateSymbols.size() != 0 )
696 {
697 m_loadedSymbols.push_back( kiSym );
698 }
699 else
700 {
701 if( part.Definition.GateSymbols.size() == 0 )
702 {
703 m_reporter->Report( wxString::Format( _( "Part definition '%s' has an incomplete "
704 "definition (no symbol definitions are "
705 "associated with it). The part has not "
706 "been loaded into the KiCad library." ),
707 part.Name ),
709 }
710
711 // Don't save in the library, but still keep it cached as some of the units might have
712 // been loaded correctly (saving us time later on), plus the part definition contains
713 // the part name, which is important to load
714 }
715
716 m_partMap.insert( { partID, kiSym } );
717
718 checkPoint();
719 }
720}
721
722
724{
725 for( std::pair<SYMBOL_ID, SYMBOL> symPair : Schematic.Symbols )
726 {
727 SYMBOL sym = symPair.second;
728
729 if( !sym.VariantID.empty() && sym.VariantParentSymbolID != sym.ID )
730 continue; // Only load master Variant
731
732 if( sym.IsComponent )
733 {
734 if( m_partMap.find( sym.PartRef.RefID ) == m_partMap.end() )
735 {
736 m_reporter->Report( wxString::Format( _( "Symbol '%s' references part '%s' which "
737 "could not be found in the library. The "
738 "symbol was not loaded" ),
740 sym.PartRef.RefID ),
742
743 continue;
744 }
745
746 if( sym.GateID.IsEmpty() )
747 sym.GateID = wxT( "A" ); // Assume Gate "A" if unspecified
748
749 PART_GATE_ID partSymbolID = { sym.PartRef.RefID, sym.GateID };
750 LIB_SYMBOL* kiSym = m_partMap.at( sym.PartRef.RefID );
751 bool copy = false;
752
753 // The symbol definition in the part either does not exist for this gate number
754 // or is different to the symbol instance. We need to reload the gate for this
755 // symbol
756 if( m_partSymbolsMap.find( partSymbolID ) == m_partSymbolsMap.end()
757 || m_partSymbolsMap.at( partSymbolID ) != sym.SymdefID )
758 {
759 kiSym = new LIB_SYMBOL( *kiSym ); // Make a copy
760 copy = true;
761 const PART& part = Parts.PartDefinitions.at( sym.PartRef.RefID );
762 loadSymbolGateAndPartFields( sym.SymdefID, part, sym.GateID, kiSym );
763 }
764
765 LIB_SYMBOL* scaledPart = getScaledLibPart( kiSym, sym.ScaleRatioNumerator,
767
768 EDA_ANGLE symOrient = ANGLE_0;
769 SCH_SYMBOL* symbol = loadSchematicSymbol( sym, *scaledPart, symOrient );
770
771 delete scaledPart;
772
773 if( copy )
774 delete kiSym;
775
776 SCH_FIELD* refField = symbol->GetField( REFERENCE_FIELD );
777
778 sym.ComponentRef.Designator.Replace( wxT( "\n" ), wxT( "\\n" ) );
779 sym.ComponentRef.Designator.Replace( wxT( "\r" ), wxT( "\\r" ) );
780 sym.ComponentRef.Designator.Replace( wxT( "\t" ), wxT( "\\t" ) );
781 sym.ComponentRef.Designator.Replace( wxT( " " ), wxT( "_" ) );
782
783 refField->SetText( sym.ComponentRef.Designator );
784 loadSymbolFieldAttribute( sym.ComponentRef.AttrLoc, symOrient, sym.Mirror, refField );
785
786 if( sym.HasPartRef )
787 {
788 SCH_FIELD* partField = symbol->FindField( PartNameFieldName );
789
790 if( !partField )
791 {
792 int fieldID = symbol->GetFieldCount();
793 partField = symbol->AddField( SCH_FIELD( VECTOR2I(), fieldID, symbol,
795 }
796
797 wxASSERT( partField->GetName() == PartNameFieldName );
798
799 wxString partname = getPart( sym.PartRef.RefID ).Name;
800 partname.Replace( wxT( "\n" ), wxT( "\\n" ) );
801 partname.Replace( wxT( "\r" ), wxT( "\\r" ) );
802 partname.Replace( wxT( "\t" ), wxT( "\\t" ) );
803 partField->SetText( partname );
804
805 loadSymbolFieldAttribute( sym.PartRef.AttrLoc, symOrient, sym.Mirror, partField );
806
808 }
809
810 for( auto& attr : sym.AttributeValues )
811 {
812 ATTRIBUTE_VALUE attrVal = attr.second;
813
814 if( attrVal.HasLocation )
815 {
816 wxString attrName = getAttributeName( attrVal.AttributeID );
817 SCH_FIELD* attrField = symbol->FindField( attrName );
818
819 if( !attrField )
820 {
821 int fieldID = symbol->GetFieldCount();
822 attrField = symbol->AddField( SCH_FIELD( VECTOR2I(), fieldID, symbol,
823 attrName ) );
824 }
825
826 wxASSERT( attrField->GetName() == attrName );
827
828 attrVal.Value.Replace( wxT( "\n" ), wxT( "\\n" ) );
829 attrVal.Value.Replace( wxT( "\r" ), wxT( "\\r" ) );
830 attrVal.Value.Replace( wxT( "\t" ), wxT( "\\t" ) );
831 attrField->SetText( attrVal.Value );
832
833 loadSymbolFieldAttribute( attrVal.AttributeLocation, symOrient, sym.Mirror,
834 attrField );
835 attrField->SetVisible( isAttributeVisible( attrVal.AttributeID ) );
836 }
837 }
838 }
839 else if( sym.IsSymbolVariant )
840 {
842 {
843 THROW_IO_ERROR( wxString::Format( _( "Symbol ID '%s' references library symbol "
844 "'%s' which could not be found in the "
845 "library. Did you export all items of the "
846 "design?" ),
847 sym.ID,
848 sym.PartRef.RefID ) );
849 }
850
851 SYMDEF_SCM libSymDef = Library.SymbolDefinitions.at( sym.SymdefID );
852
853 if( libSymDef.Terminals.size() != 1 )
854 {
855 THROW_IO_ERROR( wxString::Format( _( "Symbol ID '%s' is a signal reference or "
856 "global signal but it has too many pins. The "
857 "expected number of pins is 1 but %d were "
858 "found." ),
859 sym.ID,
860 libSymDef.Terminals.size() ) );
861 }
862
863 if( sym.SymbolVariant.Type == SYMBOLVARIANT::TYPE::GLOBALSIGNAL )
864 {
865 SYMDEF_ID symID = sym.SymdefID;
866 LIB_SYMBOL* kiPart = nullptr;
867
868 // In CADSTAR "GlobalSignal" is a special type of symbol which defines
869 // a Power Symbol. The "Alternate" name defines the default net name of
870 // the power symbol but this can be overridden in the design itself.
871 wxString libraryNetName = Library.SymbolDefinitions.at( symID ).Alternate;
872
873 // Name of the net that the symbol instance in CADSTAR refers to:
874 wxString symbolInstanceNetName = sym.SymbolVariant.Reference;
875 symbolInstanceNetName = EscapeString( symbolInstanceNetName, CTX_LIBID );
876
877 // Name of the symbol we will use for saving the part in KiCad
878 // Note: In CADSTAR all power symbols will start have the reference name be
879 // "GLOBALSIGNAL" followed by the default net name, so it makes sense to save
880 // the symbol in KiCad as the default net name as well.
881 wxString libPartName = libraryNetName;
882
883 // In CADSTAR power symbol instances can refer to a different net to that defined
884 // in the library. This causes problems in KiCad v6 as it breaks connectivity when
885 // the user decides to update all symbols from library. We handle this by creating
886 // individual versions of the power symbol for each net name.
887 if( libPartName != symbolInstanceNetName )
888 {
889 libPartName += wxT( " (" ) + symbolInstanceNetName + wxT( ")" );
890 }
891
892 if( m_powerSymLibMap.find( libPartName ) == m_powerSymLibMap.end() )
893 {
894 const LIB_SYMBOL* templatePart = loadSymdef( symID );
895 wxCHECK( templatePart, /*void*/ );
896
897 kiPart = new LIB_SYMBOL( *templatePart );
898 kiPart->SetPower();
899 kiPart->SetName( libPartName );
900 kiPart->GetValueField().SetText( symbolInstanceNetName );
901 kiPart->SetShowPinNames( false );
902 kiPart->SetShowPinNumbers( false );
903
904 std::vector<SCH_PIN*> pins = kiPart->GetAllLibPins();
905 wxCHECK( pins.size() == 1, /*void*/ );
906
907 pins.at( 0 )->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
908 pins.at( 0 )->SetName( symbolInstanceNetName );
909
910 if( libSymDef.TextLocations.find( SIGNALNAME_ORIGIN_ATTRID )
911 != libSymDef.TextLocations.end() )
912 {
913 TEXT_LOCATION& txtLoc =
915
916 VECTOR2I valPos = getKiCadLibraryPoint( txtLoc.Position, libSymDef.Origin );
917
918 kiPart->GetValueField().SetPosition( valPos );
919 kiPart->GetValueField().SetVisible( true );
920 }
921 else
922 {
923 kiPart->GetValueField().SetVisible( false );
924 }
925
926 kiPart->GetReferenceField().SetText( "#PWR" );
927 kiPart->GetReferenceField().SetVisible( false );
928 m_loadedSymbols.push_back( kiPart );
929 m_powerSymLibMap.insert( { libPartName, kiPart } );
930 }
931 else
932 {
933 kiPart = m_powerSymLibMap.at( libPartName );
934 wxASSERT( kiPart->GetValueField().GetText() == symbolInstanceNetName );
935 }
936
937 LIB_SYMBOL* scaledPart = getScaledLibPart( kiPart, sym.ScaleRatioNumerator,
939
940 EDA_ANGLE returnedOrient = ANGLE_0;
941 SCH_SYMBOL* symbol = loadSchematicSymbol( sym, *scaledPart, returnedOrient );
942 m_powerSymMap.insert( { sym.ID, symbol } );
943
944 delete scaledPart;
945 }
946 else if( sym.SymbolVariant.Type == SYMBOLVARIANT::TYPE::SIGNALREF )
947 {
948 // There should only be one pin and we'll use that to set the position
949 TERMINAL& symbolTerminal = libSymDef.Terminals.begin()->second;
950 VECTOR2I terminalPosOffset = symbolTerminal.Position - libSymDef.Origin;
951 EDA_ANGLE rotate = getAngle( sym.OrientAngle );
952
953 if( sym.Mirror )
954 rotate += ANGLE_180;
955
956 RotatePoint( terminalPosOffset, -rotate );
957
958 SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL;
959 netLabel->SetPosition( getKiCadPoint( (VECTOR2I)sym.Origin + terminalPosOffset ) );
960 netLabel->SetText( "***UNKNOWN NET****" ); // This should be later updated when we load the netlist
961 netLabel->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 50 ), schIUScale.MilsToIU( 50 ) ) );
962
963 SYMDEF_SCM symbolDef = Library.SymbolDefinitions.at( sym.SymdefID );
964
965 if( symbolDef.TextLocations.count( LINK_ORIGIN_ATTRID ) )
966 {
967 TEXT_LOCATION linkOrigin = symbolDef.TextLocations.at( LINK_ORIGIN_ATTRID );
968 applyTextSettings( netLabel, linkOrigin.TextCodeID, linkOrigin.Alignment,
969 linkOrigin.Justification );
970 }
971
972 netLabel->SetSpinStyle( getSpinStyle( sym.OrientAngle, sym.Mirror ) );
973
974 if( libSymDef.Alternate.Lower().Contains( "in" ) )
975 netLabel->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
976 else if( libSymDef.Alternate.Lower().Contains( "bi" ) )
977 netLabel->SetShape( LABEL_FLAG_SHAPE::L_BIDI );
978 else if( libSymDef.Alternate.Lower().Contains( "out" ) )
979 netLabel->SetShape( LABEL_FLAG_SHAPE::L_OUTPUT );
980 else
981 netLabel->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED );
982
983 SCH_SCREEN* screen = m_sheetMap.at( sym.LayerID )->GetScreen();
984
985 // autoplace intersheet refs
986 netLabel->AutoplaceFields( screen, false );
987
988 screen->Append( netLabel );
989 m_globalLabelsMap.insert( { sym.ID, netLabel } );
990 }
991 else
992 {
993 wxASSERT_MSG( false, "Unknown Symbol Variant." );
994 }
995 }
996 else
997 {
998 m_reporter->Report( wxString::Format( _( "Symbol ID '%s' is of an unknown type. It is "
999 "neither a symbol or a net power / symbol. "
1000 "The symbol was not loaded." ),
1001 sym.ID ),
1003 }
1004
1005 if( sym.ScaleRatioDenominator != 1 || sym.ScaleRatioNumerator != 1 )
1006 {
1007 wxString symbolName = sym.ComponentRef.Designator;
1008
1009 if( symbolName.empty() )
1010 symbolName = wxString::Format( "ID: %s", sym.ID );
1011 else
1012 symbolName += sym.GateID;
1013
1014 m_reporter->Report( wxString::Format( _( "Symbol '%s' is scaled in the original "
1015 "CADSTAR schematic but this is not supported "
1016 "in KiCad. When the symbol is reloaded from "
1017 "the library, it will revert to the original "
1018 "1:1 scale." ),
1019 symbolName,
1020 sym.PartRef.RefID ),
1022 }
1023 }
1024}
1025
1026
1028{
1029 for( std::pair<BUS_ID, BUS> busPair : Schematic.Buses )
1030 {
1031 BUS bus = busPair.second;
1032 bool firstPt = true;
1033 VERTEX last;
1034
1035 if( bus.LayerID != wxT( "NO_SHEET" ) )
1036 {
1037 SCH_SCREEN* screen = m_sheetMap.at( bus.LayerID )->GetScreen();
1038 std::shared_ptr<BUS_ALIAS> kiBusAlias = std::make_shared<BUS_ALIAS>();
1039
1040 kiBusAlias->SetName( bus.Name );
1041 kiBusAlias->SetParent( screen );
1042 screen->AddBusAlias( kiBusAlias );
1043 m_busesMap.insert( { bus.ID, kiBusAlias } );
1044
1045 SCH_LABEL* label = new SCH_LABEL();
1046
1047 wxString busname = HandleTextOverbar( bus.Name );
1048
1049 label->SetText( wxT( "{" ) + busname + wxT( "}" ) );
1050 label->SetVisible( true );
1051 screen->Append( label );
1052
1053 SHAPE_LINE_CHAIN busLineChain; // to compute nearest segment to bus label
1054
1055 for( const VERTEX& cur : bus.Shape.Vertices )
1056 {
1057 busLineChain.Append( getKiCadPoint( cur.End ) );
1058
1059 if( firstPt )
1060 {
1061 last = cur;
1062 firstPt = false;
1063
1064 if( !bus.HasBusLabel )
1065 {
1066 // Add a bus label on the starting point if the original CADSTAR design
1067 // does not have an explicit label
1068 label->SetPosition( getKiCadPoint( last.End ) );
1069 }
1070
1071 continue;
1072 }
1073
1074
1075 SCH_LINE* kiBus = new SCH_LINE();
1076
1077 kiBus->SetStartPoint( getKiCadPoint( last.End ) );
1078 kiBus->SetEndPoint( getKiCadPoint( cur.End ) );
1079 kiBus->SetLayer( LAYER_BUS );
1080 kiBus->SetLineWidth( getLineThickness( bus.LineCodeID ) );
1081 screen->Append( kiBus );
1082
1083 last = cur;
1084 }
1085
1086 if( bus.HasBusLabel )
1087 {
1088 //lets find the closest point in the busline to the label
1089 VECTOR2I busLabelLoc = getKiCadPoint( bus.BusLabel.Position );
1090 VECTOR2I nearestPt = busLineChain.NearestPoint( busLabelLoc );
1091
1092 label->SetPosition( nearestPt );
1093
1095 bus.BusLabel.Justification );
1096
1097 // Re-set bus name as it might have been "double-escaped" after applyTextSettings
1098 label->SetText( wxT( "{" ) + busname + wxT( "}" ) );
1099
1100 // Note orientation of the bus label will be determined in loadNets
1101 // (the position of the wire will determine how best to place the bus label)
1102 }
1103 }
1104 }
1105}
1106
1107
1109{
1110 for( std::pair<NET_ID, NET_SCH> netPair : Schematic.Nets )
1111 {
1112 NET_SCH net = netPair.second;
1113 wxString netName = net.Name;
1114 std::map<NETELEMENT_ID, SCH_LABEL*> netlabels;
1115
1116 if( netName.IsEmpty() )
1117 netName = wxString::Format( "$%ld", net.SignalNum );
1118
1119 netName = HandleTextOverbar( netName );
1120
1121 for( std::pair<NETELEMENT_ID, NET_SCH::SYM_TERM> terminalPair : net.Terminals )
1122 {
1123 NET_SCH::SYM_TERM netTerm = terminalPair.second;
1124
1125 if( m_powerSymMap.find( netTerm.SymbolID ) != m_powerSymMap.end() )
1126 {
1127 SCH_FIELD* val = m_powerSymMap.at( netTerm.SymbolID )->GetField( VALUE_FIELD );
1128 val->SetText( netName );
1129 val->SetBold( false );
1130 val->SetVisible( false );
1131
1132 if( netTerm.HasNetLabel )
1133 {
1134 val->SetVisible( true );
1135 val->SetPosition( getKiCadPoint( netTerm.NetLabel.Position ) );
1136
1137 applyTextSettings( val, netTerm.NetLabel.TextCodeID, netTerm.NetLabel.Alignment,
1138 netTerm.NetLabel.Justification, netTerm.NetLabel.OrientAngle,
1139 netTerm.NetLabel.Mirror );
1140 }
1141 }
1142 else if( m_globalLabelsMap.find( netTerm.SymbolID ) != m_globalLabelsMap.end() )
1143 {
1144 m_globalLabelsMap.at( netTerm.SymbolID )->SetText( netName );
1145
1146 LAYER_ID sheet = Schematic.Symbols.at( netTerm.SymbolID ).LayerID;
1147
1148 if( m_sheetMap.count( sheet ) )
1149 {
1150 SCH_SCREEN* screen = m_sheetMap.at( sheet )->GetScreen();
1151
1152 // autoplace intersheet refs again since we've changed the name
1153 m_globalLabelsMap.at( netTerm.SymbolID )->AutoplaceFields( screen, false );
1154 }
1155 }
1156 else if( !net.Name.IsEmpty() && Schematic.Symbols.count( netTerm.SymbolID )
1157 && netTerm.HasNetLabel )
1158 {
1159 // This is a named net that connects to a schematic symbol pin - we need to put a label
1160 SCH_LABEL* label = new SCH_LABEL();
1161 label->SetText( netName );
1162
1163 POINT pinLocation = getLocationOfNetElement( net, netTerm.ID );
1164 label->SetPosition( getKiCadPoint( pinLocation ) );
1165 label->SetVisible( true );
1166
1167 applyTextSettings( label, netTerm.NetLabel.TextCodeID, netTerm.NetLabel.Alignment,
1168 netTerm.NetLabel.Justification );
1169
1170 netlabels.insert( { netTerm.ID, label } );
1171
1172 LAYER_ID sheet = Schematic.Symbols.at( netTerm.SymbolID ).LayerID;
1173 m_sheetMap.at( sheet )->GetScreen()->Append( label );
1174 }
1175 }
1176
1177 auto getHierarchicalLabel =
1178 [&]( const NETELEMENT_ID& aNode ) -> SCH_HIERLABEL*
1179 {
1180 if( aNode.Contains( "BLKT" ) )
1181 {
1182 NET_SCH::BLOCK_TERM blockTerm = net.BlockTerminals.at( aNode );
1183 BLOCK_PIN_ID blockPinID = std::make_pair( blockTerm.BlockID,
1184 blockTerm.TerminalID );
1185
1186 if( m_sheetPinMap.find( blockPinID ) != m_sheetPinMap.end() )
1187 return m_sheetPinMap.at( blockPinID );
1188 }
1189
1190 return nullptr;
1191 };
1192
1193 //Add net name to all hierarchical pins (block terminals in CADSTAR)
1194 for( std::pair<NETELEMENT_ID, NET_SCH::BLOCK_TERM> blockPair : net.BlockTerminals )
1195 {
1196 SCH_HIERLABEL* label = getHierarchicalLabel( blockPair.first );
1197
1198 if( label )
1199 label->SetText( netName );
1200 }
1201
1202 // Load all bus entries and add net label if required
1203 for( std::pair<NETELEMENT_ID, NET_SCH::BUS_TERM> busPair : net.BusTerminals )
1204 {
1205 NET_SCH::BUS_TERM busTerm = busPair.second;
1206 BUS bus = Schematic.Buses.at( busTerm.BusID );
1207
1208 if( !alg::contains( m_busesMap.at( bus.ID )->Members(), netName ) )
1209 m_busesMap.at( bus.ID )->Members().emplace_back( netName );
1210
1211 SCH_BUS_WIRE_ENTRY* busEntry =
1212 new SCH_BUS_WIRE_ENTRY( getKiCadPoint( busTerm.FirstPoint ), false );
1213
1214 VECTOR2I size =
1215 getKiCadPoint( busTerm.SecondPoint ) - getKiCadPoint( busTerm.FirstPoint );
1216 busEntry->SetSize( VECTOR2I( size.x, size.y ) );
1217
1218 m_sheetMap.at( bus.LayerID )->GetScreen()->Append( busEntry );
1219
1220 // Always add a label at bus terminals to ensure connectivity.
1221 // If the original design does not have a label, just make it very small
1222 // to keep connectivity but make the design look visually similar to
1223 // the original.
1224 SCH_LABEL* label = new SCH_LABEL();
1225 label->SetText( netName );
1226 label->SetPosition( getKiCadPoint( busTerm.SecondPoint ) );
1227 label->SetVisible( true );
1228
1229 if( busTerm.HasNetLabel )
1230 {
1231 applyTextSettings( label, busTerm.NetLabel.TextCodeID, busTerm.NetLabel.Alignment,
1232 busTerm.NetLabel.Justification );
1233 }
1234 else
1235 {
1237 }
1238
1239 netlabels.insert( { busTerm.ID, label } );
1240 m_sheetMap.at( bus.LayerID )->GetScreen()->Append( label );
1241 }
1242
1243 for( std::pair<NETELEMENT_ID, NET_SCH::DANGLER> danglerPair : net.Danglers )
1244 {
1245 NET_SCH::DANGLER dangler = danglerPair.second;
1246
1247 SCH_LABEL* label = new SCH_LABEL();
1248 label->SetPosition( getKiCadPoint( dangler.Position ) );
1249 label->SetVisible( true );
1250
1251 if( dangler.HasNetLabel )
1252 {
1253 applyTextSettings( label, dangler.NetLabel.TextCodeID, dangler.NetLabel.Alignment,
1254 dangler.NetLabel.Justification );
1255 }
1256
1257 label->SetText( netName ); // set text after applying settings to avoid double-escaping
1258 netlabels.insert( { dangler.ID, label } );
1259
1260 m_sheetMap.at( dangler.LayerID )->GetScreen()->Append( label );
1261 }
1262
1263 for( NET_SCH::CONNECTION_SCH conn : net.Connections )
1264 {
1265 if( conn.LayerID == wxT( "NO_SHEET" ) )
1266 continue; // No point loading virtual connections. KiCad handles that internally
1267
1268 POINT start = getLocationOfNetElement( net, conn.StartNode );
1269 POINT end = getLocationOfNetElement( net, conn.EndNode );
1270
1271 if( start.x == UNDEFINED_VALUE || end.x == UNDEFINED_VALUE )
1272 continue;
1273
1274 // Connections in CADSTAR are always implied between symbols even if the route
1275 // doesn't start and end exactly at the connection points
1276 if( conn.Path.size() < 1 || conn.Path.front() != start )
1277 conn.Path.insert( conn.Path.begin(), start );
1278
1279 if( conn.Path.size() < 2 || conn.Path.back() != end )
1280 conn.Path.push_back( end );
1281
1282 bool firstPt = true;
1283 bool secondPt = false;
1284 VECTOR2I last;
1285 SCH_LINE* wire = nullptr;
1286
1287 SHAPE_LINE_CHAIN wireChain; // Create a temp. line chain representing the connection
1288
1289 for( const POINT& pt : conn.Path )
1290 wireChain.Append( getKiCadPoint( pt ) );
1291
1292 // AUTO-FIX SHEET PINS
1293 //--------------------
1294 // KiCad constrains the sheet pin on the edge of the sheet object whereas in
1295 // CADSTAR it can be anywhere. Let's find the intersection of the wires with the sheet
1296 // and place the hierarchical
1297 std::vector<NETELEMENT_ID> nodes;
1298 nodes.push_back( conn.StartNode );
1299 nodes.push_back( conn.EndNode );
1300
1301 for( const NETELEMENT_ID& node : nodes )
1302 {
1303 SCH_HIERLABEL* sheetPin = getHierarchicalLabel( node );
1304
1305 if( sheetPin )
1306 {
1307 if( sheetPin->Type() == SCH_SHEET_PIN_T
1308 && SCH_SHEET::ClassOf( sheetPin->GetParent() ) )
1309 {
1310 SCH_SHEET* parentSheet = static_cast<SCH_SHEET*>( sheetPin->GetParent() );
1311 VECTOR2I sheetSize = parentSheet->GetSize();
1312 VECTOR2I sheetPosition = parentSheet->GetPosition();
1313
1314 int leftSide = sheetPosition.x;
1315 int rightSide = sheetPosition.x + sheetSize.x;
1316 int topSide = sheetPosition.y;
1317 int botSide = sheetPosition.y + sheetSize.y;
1318
1319 SHAPE_LINE_CHAIN sheetEdge;
1320
1321 sheetEdge.Append( leftSide, topSide );
1322 sheetEdge.Append( rightSide, topSide );
1323 sheetEdge.Append( rightSide, botSide );
1324 sheetEdge.Append( leftSide, botSide );
1325 sheetEdge.Append( leftSide, topSide );
1326
1327 SHAPE_LINE_CHAIN::INTERSECTIONS wireToSheetIntersects;
1328
1329 if( !wireChain.Intersect( sheetEdge, wireToSheetIntersects ) )
1330 {
1331 // The block terminal is outside the block shape in the original
1332 // CADSTAR design. Since KiCad's Sheet Pin will already be constrained
1333 // on the edge, we will simply join to it with a straight line.
1334 if( node == conn.StartNode )
1335 wireChain = wireChain.Reverse();
1336
1337 wireChain.Append( sheetPin->GetPosition() );
1338
1339 if( node == conn.StartNode )
1340 wireChain = wireChain.Reverse();
1341 }
1342 else
1343 {
1344 // The block terminal is either inside or on the shape edge. Lets use
1345 // the first intersection point.
1346 VECTOR2I intsctPt = wireToSheetIntersects.at( 0 ).p;
1347 int intsctIndx = wireChain.FindSegment( intsctPt );
1348 wxASSERT_MSG( intsctIndx != -1, "Can't find intersecting segment" );
1349
1350 if( node == conn.StartNode )
1351 wireChain.Replace( 0, intsctIndx, intsctPt );
1352 else
1353 wireChain.Replace( intsctIndx + 1, /*end index*/ -1, intsctPt );
1354
1355 sheetPin->SetPosition( intsctPt );
1356 }
1357 }
1358 }
1359 }
1360
1361 auto fixNetLabelsAndSheetPins =
1362 [&]( const EDA_ANGLE& aWireAngle, NETELEMENT_ID& aNetEleID )
1363 {
1364 SPIN_STYLE spin = getSpinStyle( aWireAngle );
1365
1366 if( netlabels.find( aNetEleID ) != netlabels.end() )
1367 netlabels.at( aNetEleID )->SetSpinStyle( spin.MirrorY() );
1368
1369 SCH_HIERLABEL* sheetPin = getHierarchicalLabel( aNetEleID );
1370
1371 if( sheetPin )
1372 sheetPin->SetSpinStyle( spin.MirrorX() );
1373 };
1374
1375 // Now we can load the wires and fix the label orientations
1376 for( const VECTOR2I& pt : wireChain.CPoints() )
1377 {
1378 if( firstPt )
1379 {
1380 last = pt;
1381 firstPt = false;
1382 secondPt = true;
1383 continue;
1384 }
1385
1386 if( secondPt )
1387 {
1388 secondPt = false;
1389
1390 EDA_ANGLE wireAngle( last - pt );
1391 fixNetLabelsAndSheetPins( wireAngle, conn.StartNode );
1392 }
1393
1394 wire = new SCH_LINE();
1395
1396 wire->SetStartPoint( last );
1397 wire->SetEndPoint( pt );
1398 wire->SetLayer( LAYER_WIRE );
1399
1400 if( !conn.ConnectionLineCode.IsEmpty() )
1401 wire->SetLineWidth( getLineThickness( conn.ConnectionLineCode ) );
1402
1403 last = pt;
1404
1405 m_sheetMap.at( conn.LayerID )->GetScreen()->Append( wire );
1406 }
1407
1408 //Fix labels on the end wire
1409 if( wire )
1410 {
1411 EDA_ANGLE wireAngle( wire->GetEndPoint() - wire->GetStartPoint() );
1412 fixNetLabelsAndSheetPins( wireAngle, conn.EndNode );
1413 }
1414 }
1415
1416 for( std::pair<NETELEMENT_ID, NET_SCH::JUNCTION_SCH> juncPair : net.Junctions )
1417 {
1418 NET_SCH::JUNCTION_SCH junc = juncPair.second;
1419
1420 SCH_JUNCTION* kiJunc = new SCH_JUNCTION();
1421
1422 kiJunc->SetPosition( getKiCadPoint( junc.Location ) );
1423 m_sheetMap.at( junc.LayerID )->GetScreen()->Append( kiJunc );
1424
1425 if( junc.HasNetLabel )
1426 {
1427 // In CADSTAR the label can be placed anywhere, but in KiCad it has to be placed
1428 // in the same location as the junction for it to be connected to it.
1429 SCH_LABEL* label = new SCH_LABEL();
1430 label->SetText( netName );
1431 label->SetPosition( getKiCadPoint( junc.Location ) );
1432 label->SetVisible( true );
1433
1434 EDA_ANGLE labelAngle = getAngle( junc.NetLabel.OrientAngle );
1435 SPIN_STYLE spin = getSpinStyle( labelAngle );
1436
1437 label->SetSpinStyle( spin );
1438
1439 m_sheetMap.at( junc.LayerID )->GetScreen()->Append( label );
1440 }
1441 }
1442 }
1443}
1444
1445
1447{
1448 for( std::pair<FIGURE_ID, FIGURE> figPair : Schematic.Figures )
1449 {
1450 FIGURE fig = figPair.second;
1451
1452 loadFigure( fig, fig.LayerID, LAYER_NOTES );
1453 }
1454}
1455
1456
1458{
1459 for( std::pair<TEXT_ID, TEXT> textPair : Schematic.Texts )
1460 {
1461 TEXT txt = textPair.second;
1462
1463 SCH_TEXT* kiTxt = getKiCadSchText( txt );
1464 loadItemOntoKiCadSheet( txt.LayerID, kiTxt );
1465 }
1466}
1467
1468
1470{
1471 for( std::pair<DOCUMENTATION_SYMBOL_ID, DOCUMENTATION_SYMBOL> docSymPair :
1473 {
1474 DOCUMENTATION_SYMBOL docSym = docSymPair.second;
1475
1476 if( Library.SymbolDefinitions.find( docSym.SymdefID ) == Library.SymbolDefinitions.end() )
1477 {
1478 m_reporter->Report( wxString::Format( _( "Documentation Symbol '%s' refers to symbol "
1479 "definition ID '%s' which does not exist in "
1480 "the library. The symbol was not loaded." ),
1481 docSym.ID,
1482 docSym.SymdefID ),
1484 continue;
1485 }
1486
1487 SYMDEF_SCM docSymDef = Library.SymbolDefinitions.at( docSym.SymdefID );
1488 VECTOR2I moveVector = getKiCadPoint( docSym.Origin ) - getKiCadPoint( docSymDef.Origin );
1489 EDA_ANGLE rotationAngle = getAngle( docSym.OrientAngle );
1490 double scalingFactor = (double) docSym.ScaleRatioNumerator
1491 / (double) docSym.ScaleRatioDenominator;
1492 VECTOR2I centreOfTransform = getKiCadPoint( docSymDef.Origin );
1493 bool mirrorInvert = docSym.Mirror;
1494
1495 for( std::pair<FIGURE_ID, FIGURE> figPair : docSymDef.Figures )
1496 {
1497 FIGURE fig = figPair.second;
1498
1499 loadFigure( fig, docSym.LayerID, LAYER_NOTES, moveVector, rotationAngle, scalingFactor,
1500 centreOfTransform, mirrorInvert );
1501 }
1502
1503 for( std::pair<TEXT_ID, TEXT> textPair : docSymDef.Texts )
1504 {
1505 TEXT txt = textPair.second;
1506
1507 txt.Mirror = ( txt.Mirror ) ? !mirrorInvert : mirrorInvert;
1508 txt.OrientAngle = docSym.OrientAngle - txt.OrientAngle;
1509
1510 SCH_TEXT* kiTxt = getKiCadSchText( txt );
1511
1512 VECTOR2I newPosition = applyTransform( kiTxt->GetPosition(), moveVector, rotationAngle,
1513 scalingFactor, centreOfTransform, mirrorInvert );
1514
1515 int newTxtWidth = KiROUND( kiTxt->GetTextWidth() * scalingFactor );
1516 int newTxtHeight = KiROUND( kiTxt->GetTextHeight() * scalingFactor );
1517 int newTxtThickness = KiROUND( kiTxt->GetTextThickness() * scalingFactor );
1518
1519 kiTxt->SetPosition( newPosition );
1520 kiTxt->SetTextWidth( newTxtWidth );
1521 kiTxt->SetTextHeight( newTxtHeight );
1522 kiTxt->SetTextThickness( newTxtThickness );
1523
1524 loadItemOntoKiCadSheet( docSym.LayerID, kiTxt );
1525 }
1526 }
1527}
1528
1529
1531{
1532 auto findAndReplaceTextField =
1533 [&]( TEXT_FIELD_NAME aField, wxString aValue )
1534 {
1535 if( m_context.TextFieldToValuesMap.find( aField ) != m_context.TextFieldToValuesMap.end() )
1536 {
1537 if( m_context.TextFieldToValuesMap.at( aField ) != aValue )
1538 {
1539 m_context.TextFieldToValuesMap.at( aField ) = aValue;
1540 m_context.InconsistentTextFields.insert( aField );
1541 return false;
1542 }
1543 }
1544 else
1545 {
1546 m_context.TextFieldToValuesMap.insert( { aField, aValue } );
1547 }
1548
1549 return true;
1550 };
1551
1552 PROJECT* pj = &m_schematic->Prj();
1553
1554 if( pj )
1555 {
1556 std::map<wxString, wxString>& txtVars = pj->GetTextVars();
1557
1558 // Most of the design text fields can be derived from other elements
1559 if( Schematic.VariantHierarchy.Variants.size() > 0 )
1560 {
1561 VARIANT loadedVar = Schematic.VariantHierarchy.Variants.begin()->second;
1562
1563 findAndReplaceTextField( TEXT_FIELD_NAME::VARIANT_NAME, loadedVar.Name );
1564 findAndReplaceTextField( TEXT_FIELD_NAME::VARIANT_DESCRIPTION, loadedVar.Description );
1565 }
1566
1567 findAndReplaceTextField( TEXT_FIELD_NAME::DESIGN_TITLE, Header.JobTitle );
1568
1569 for( std::pair<TEXT_FIELD_NAME, wxString> txtvalue : m_context.TextFieldToValuesMap )
1570 {
1571 wxString varName = CADSTAR_TO_KICAD_FIELDS.at( txtvalue.first );
1572 wxString varValue = txtvalue.second;
1573
1574 txtVars.insert( { varName, varValue } );
1575 }
1576
1577 for( std::pair<wxString, wxString> txtvalue : m_context.FilenamesToTextMap )
1578 {
1579 wxString varName = txtvalue.first;
1580 wxString varValue = txtvalue.second;
1581
1582 txtVars.insert( { varName, varValue } );
1583 }
1584 }
1585 else
1586 {
1587 m_reporter->Report( _( "Text Variables could not be set as there is no project attached." ),
1589 }
1590}
1591
1592
1593SCH_FIELD*
1595 std::unique_ptr<LIB_SYMBOL>& aKiCadSymbol )
1596{
1597 // First Check if field already exists
1598 SCH_FIELD* existingField = aKiCadSymbol->FindField( aFieldName );
1599
1600 if( existingField != nullptr )
1601 return existingField;
1602
1603 int newfieldID = aKiCadSymbol->GetFieldCount();
1604 SCH_FIELD* newfield = new SCH_FIELD( aKiCadSymbol.get(), newfieldID );
1605 newfield->SetName( aFieldName );
1606 newfield->SetVisible( false );
1607 aKiCadSymbol->AddField( newfield );
1608 /*
1609 @todo we should load that a field is a URL by checking if it starts with "Link"
1610 e.g.:
1611 if( aFieldName.Lower().StartsWith( "link" ) )
1612 newfield->SetAsURL*/
1613
1614 return newfield;
1615}
1616
1617
1619{
1620 wxCHECK( Library.SymbolDefinitions.find( aSymdefID ) != Library.SymbolDefinitions.end(), nullptr );
1621
1622 if( m_symDefMap.count( aSymdefID ) )
1623 return m_symDefMap.at( aSymdefID ).get(); // return a non-owning ptr
1624
1625 SYMDEF_SCM csSym = Library.SymbolDefinitions.at( aSymdefID );
1626 std::unique_ptr<LIB_SYMBOL> kiSym = std::make_unique<LIB_SYMBOL>( csSym.BuildLibName() );
1627 const int gateNumber = 1; // Always load to gate "A" - we will change the unit later
1628
1629 // Load Graphical Figures
1630 for( std::pair<FIGURE_ID, FIGURE> figPair : csSym.Figures )
1631 {
1632 FIGURE fig = figPair.second;
1633 int lineThickness = getLineThickness( fig.LineCodeID );
1634 LINE_STYLE linestyle = getLineStyle( fig.LineCodeID );
1635
1636 if( fig.Shape.Type == SHAPE_TYPE::OPENSHAPE )
1637 {
1638 loadLibrarySymbolShapeVertices( fig.Shape.Vertices, csSym.Origin, kiSym.get(),
1639 gateNumber,
1640 lineThickness );
1641 }
1642 else
1643 {
1644 SCH_SHAPE* shape = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
1645
1647 [&]( const VECTOR2I& aPt )
1648 {
1649 return getKiCadLibraryPoint( aPt, csSym.Origin );
1650 },
1651 ARC_ACCURACY ) );
1652
1653 shape->SetUnit( gateNumber );
1654
1655 shape->SetStroke( STROKE_PARAMS( lineThickness, linestyle ) );
1656
1657 if( fig.Shape.Type == SHAPE_TYPE::SOLID )
1658 shape->SetFillMode( FILL_T::FILLED_SHAPE );
1659 else if( fig.Shape.Type == SHAPE_TYPE::OUTLINE )
1660 shape->SetFillMode( FILL_T::NO_FILL );
1661 else if( fig.Shape.Type == SHAPE_TYPE::HATCHED ) // We don't have an equivalent
1662 shape->SetFillMode( FILL_T::FILLED_WITH_BG_BODYCOLOR );
1663
1664 kiSym->AddDrawItem( shape );
1665 }
1666 }
1667
1668 PINNUM_TO_TERMINAL_MAP pinNumToTerminals;
1669
1670 // Load Pins
1671 for( std::pair<TERMINAL_ID, TERMINAL> termPair : csSym.Terminals )
1672 {
1673 TERMINAL term = termPair.second;
1674 wxString pinNum = wxString::Format( "%ld", term.ID );
1675 wxString pinName = wxEmptyString;
1676 std::unique_ptr<SCH_PIN> pin = std::make_unique<SCH_PIN>( kiSym.get() );
1677
1678 // Assume passive pin for now (we will set it later once we load the parts)
1679 pin->SetType( ELECTRICAL_PINTYPE::PT_PASSIVE );
1680
1681 pin->SetPosition( getKiCadLibraryPoint( term.Position, csSym.Origin ) );
1682 pin->SetLength( 0 ); //CADSTAR Pins are just a point (have no length)
1683 pin->SetShape( GRAPHIC_PINSHAPE::LINE );
1684 pin->SetUnit( gateNumber );
1685 pin->SetNumber( pinNum );
1686 pin->SetName( pinName );
1687
1688 // TC0 is the default CADSTAR text size for name/number if none specified
1689 int pinNumberHeight = getTextHeightFromTextCode( wxT( "TC0" ) );
1690 int pinNameHeight = getTextHeightFromTextCode( wxT( "TC0" ) );
1691
1692 if( csSym.PinNumberLocations.count( term.ID ) )
1693 {
1694 PIN_NUM_LABEL_LOC pinNumLocation = csSym.PinNumberLocations.at( term.ID );
1695 pinNumberHeight = getTextHeightFromTextCode( pinNumLocation.TextCodeID );
1696 }
1697
1698 if( csSym.PinLabelLocations.count( term.ID ) )
1699 {
1700 PIN_NUM_LABEL_LOC pinNameLocation = csSym.PinLabelLocations.at( term.ID );
1701 pinNameHeight = getTextHeightFromTextCode( pinNameLocation.TextCodeID );
1702 }
1703
1704 pin->SetNumberTextSize( pinNumberHeight );
1705 pin->SetNameTextSize( pinNameHeight );
1706
1707 pinNumToTerminals.insert( { pin->GetNumber(), term.ID } );
1708 kiSym->AddDrawItem( pin.release() );
1709 }
1710
1711 m_symDefTerminalsMap.insert( { aSymdefID, pinNumToTerminals } );
1712 fixUpLibraryPins( kiSym.get(), gateNumber );
1713
1714
1715 // Load Text items
1716 for( std::pair<TEXT_ID, TEXT> textPair : csSym.Texts )
1717 {
1718 TEXT csText = textPair.second;
1719 VECTOR2I pos = getKiCadLibraryPoint( csText.Position, csSym.Origin );
1720 auto libtext = std::make_unique<SCH_TEXT>( pos, csText.Text, LAYER_DEVICE );
1721
1722 libtext->SetUnit( gateNumber );
1723 libtext->SetPosition( getKiCadLibraryPoint( csText.Position, csSym.Origin ) );
1724 libtext->SetMultilineAllowed( true ); // temporarily so that we calculate bbox correctly
1725
1726 applyTextSettings( libtext.get(), csText.TextCodeID, csText.Alignment, csText.Justification,
1727 csText.OrientAngle, csText.Mirror );
1728
1729 // Split out multi line text items into individual text elements
1730 if( csText.Text.Contains( "\n" ) )
1731 {
1732 wxArrayString strings;
1733 wxStringSplit( csText.Text, strings, '\n' );
1734 wxPoint firstLinePos;
1735
1736 for( size_t ii = 0; ii < strings.size(); ++ii )
1737 {
1738 BOX2I bbox = libtext->GetTextBox( ii );
1739 VECTOR2I linePos = { bbox.GetLeft(), -bbox.GetBottom() };
1740
1741 RotatePoint( linePos, libtext->GetTextPos(), -libtext->GetTextAngle() );
1742
1743 SCH_TEXT* textLine = static_cast<SCH_TEXT*>( libtext->Duplicate() );
1744 textLine->SetText( strings[ii] );
1747 textLine->SetTextPos( linePos );
1748
1749 // Multiline text not allowed in LIB_TEXT
1750 textLine->SetMultilineAllowed( false );
1751 kiSym->AddDrawItem( textLine );
1752 }
1753 }
1754 else
1755 {
1756 // Multiline text not allowed in LIB_TEXT
1757 libtext->SetMultilineAllowed( false );
1758 kiSym->AddDrawItem( libtext.release() );
1759 }
1760 }
1761
1762 // CADSTAR uses TC1 when fields don't have explicit text/attribute location
1763 static const TEXTCODE_ID defaultTextCode = "TC1";
1764
1765 // Load field locations (Attributes in CADSTAR)
1766
1767 // Symbol name (e.g. R1)
1768 if( csSym.TextLocations.count( SYMBOL_NAME_ATTRID ) )
1769 {
1770 TEXT_LOCATION& textLoc = csSym.TextLocations.at( SYMBOL_NAME_ATTRID );
1771 applyToLibraryFieldAttribute( textLoc, csSym.Origin, &kiSym->GetReferenceField() );
1772 }
1773 else
1774 {
1775 applyTextCodeIfExists( &kiSym->GetReferenceField(), defaultTextCode );
1776 }
1777
1778 // Always add the part name field (even if it doesn't have a specific location defined)
1779 SCH_FIELD* partField = addNewFieldToSymbol( PartNameFieldName, kiSym );
1780 wxCHECK( partField, nullptr );
1781 wxASSERT( partField->GetName() == PartNameFieldName );
1782
1783 if( csSym.TextLocations.count( PART_NAME_ATTRID ) )
1784 {
1785 TEXT_LOCATION& textLoc = csSym.TextLocations.at( PART_NAME_ATTRID );
1786 applyToLibraryFieldAttribute( textLoc, csSym.Origin, partField );
1787 }
1788 else
1789 {
1790 applyTextCodeIfExists( partField, defaultTextCode );
1791 }
1792
1794
1795
1796 for( auto& [attributeId, textLocation] : csSym.TextLocations )
1797 {
1798 if( attributeId == PART_NAME_ATTRID || attributeId == SYMBOL_NAME_ATTRID
1799 || attributeId == SIGNALNAME_ORIGIN_ATTRID || attributeId == LINK_ORIGIN_ATTRID )
1800 {
1801 continue;
1802 }
1803
1804 wxString attributeName = getAttributeName( attributeId );
1805 SCH_FIELD* field = addNewFieldToSymbol( attributeName, kiSym );
1806 applyToLibraryFieldAttribute( textLocation, csSym.Origin, field );
1807 }
1808
1809
1810 for( auto& [attributeId, attrValue] : csSym.AttributeValues )
1811 {
1812 if( attributeId == PART_NAME_ATTRID || attributeId == SYMBOL_NAME_ATTRID
1813 || attributeId == SIGNALNAME_ORIGIN_ATTRID || attributeId == LINK_ORIGIN_ATTRID )
1814 {
1815 continue;
1816 }
1817
1818 wxString attributeName = getAttributeName( attributeId );
1819 SCH_FIELD* field = addNewFieldToSymbol( attributeName, kiSym );
1820
1821 if( attrValue.HasLocation )
1822 applyToLibraryFieldAttribute( attrValue.AttributeLocation, csSym.Origin, field );
1823 else
1824 applyTextCodeIfExists( field, defaultTextCode );
1825 }
1826
1827
1828 m_symDefMap.insert( { aSymdefID, std::move( kiSym ) } );
1829
1830 return m_symDefMap.at( aSymdefID ).get(); // return a non-owning ptr
1831}
1832
1833
1835 const PART& aCadstarPart,
1836 const GATE_ID& aGateID,
1837 LIB_SYMBOL* aSymbol )
1838{
1839 wxCHECK( Library.SymbolDefinitions.find( aSymdefID ) != Library.SymbolDefinitions.end(), /*void*/ );
1840
1841 std::unique_ptr<LIB_SYMBOL> kiSymDef( loadSymdef( aSymdefID )->Duplicate() );
1842 wxCHECK( kiSymDef, /*void*/ );
1843
1844 //todo: need to use unique_ptr more. For now just create it here and release at end of function
1845 std::unique_ptr<LIB_SYMBOL> tempSymbol( aSymbol );
1846
1847 // Update the pin numbers to match those defined in the Cadstar part
1848 TERMINAL_TO_PINNUM_MAP pinNumMap;
1849
1850 for( auto&& [storedPinNum, termID] : m_symDefTerminalsMap[aSymdefID] )
1851 {
1852 PART::DEFINITION::PIN csPin = getPartDefinitionPin( aCadstarPart, aGateID, termID );
1853 SCH_PIN* pin = kiSymDef->GetPin( storedPinNum );
1854
1855 wxString pinName = HandleTextOverbar( csPin.Label );
1856 wxString pinNum = HandleTextOverbar( csPin.Name );
1857
1858 if( pinNum.IsEmpty() )
1859 {
1860 if( !csPin.Identifier.IsEmpty() )
1861 pinNum = csPin.Identifier;
1862 else if( csPin.ID == UNDEFINED_VALUE )
1863 pinNum = wxString::Format( "%ld", termID );
1864 else
1865 pinNum = wxString::Format( "%ld", csPin.ID );
1866 }
1867
1868 pin->SetType( getKiCadPinType( csPin.Type ) );
1869 pin->SetNumber( pinNum );
1870 pin->SetName( pinName );
1871
1872 pinNumMap.insert( { termID, pinNum } );
1873 }
1874
1875 m_pinNumsMap.insert( { aCadstarPart.ID + aGateID, pinNumMap } );
1876
1877 // COPY ITEMS
1878 int gateNumber = getKiCadUnitNumberFromGate( aGateID );
1879 copySymbolItems( kiSymDef, tempSymbol, gateNumber );
1880
1881 // Hide the value field for now (it might get unhidden if an attribute exists in the cadstar
1882 // design with the text "Value"
1883 tempSymbol->GetValueField().SetVisible( false );
1884
1885
1886 SCH_FIELD* partNameField = tempSymbol->FindField( PartNameFieldName );
1887
1888 if( partNameField )
1889 partNameField->SetText( EscapeFieldText( aCadstarPart.Name ) );
1890
1891 const POINT& symDefOrigin = Library.SymbolDefinitions.at( aSymdefID ).Origin;
1892 wxString footprintRefName = wxEmptyString;
1893 wxString footprintAlternateName = wxEmptyString;
1894
1895 auto loadLibraryField = [&]( const ATTRIBUTE_VALUE& aAttributeVal )
1896 {
1897 wxString attrName = getAttributeName( aAttributeVal.AttributeID );
1898
1899 // Remove invalid field characters
1900 wxString attributeValue = aAttributeVal.Value;
1901 attributeValue.Replace( wxT( "\n" ), wxT( "\\n" ) );
1902 attributeValue.Replace( wxT( "\r" ), wxT( "\\r" ) );
1903 attributeValue.Replace( wxT( "\t" ), wxT( "\\t" ) );
1904
1905 //TODO: Handle "links": In cadstar a field can be a "link" if its name starts
1906 // with the characters "Link ". Need to figure out how to convert them to
1907 // equivalent in KiCad.
1908
1909 if( attrName == wxT( "(PartDefinitionNameStem)" ) )
1910 {
1911 //Space not allowed in Reference field
1912 attributeValue.Replace( wxT( " " ), "_" );
1913 tempSymbol->GetReferenceField().SetText( attributeValue );
1914 return;
1915 }
1916 else if( attrName == wxT( "(PartDescription)" ) )
1917 {
1918 tempSymbol->SetDescription( attributeValue );
1919 return;
1920 }
1921 else if( attrName == wxT( "(PartDefinitionReferenceName)" ) )
1922 {
1923 footprintRefName = attributeValue;
1924 return;
1925 }
1926 else if( attrName == wxT( "(PartDefinitionAlternateName)" ) )
1927 {
1928 footprintAlternateName = attributeValue;
1929 return;
1930 }
1931
1932 bool attrIsNew = tempSymbol->FindField( attrName ) == nullptr;
1933 SCH_FIELD* attrField = addNewFieldToSymbol( attrName, tempSymbol );
1934
1935 wxASSERT( attrField->GetName() == attrName );
1936 attrField->SetText( aAttributeVal.Value );
1937 attrField->SetUnit( gateNumber );
1938
1939 const ATTRIBUTE_ID& attrid = aAttributeVal.AttributeID;
1940 attrField->SetVisible( isAttributeVisible( attrid ) );
1941
1942 if( aAttributeVal.HasLocation )
1943 {
1944 // Check if the part itself defined a location for the field
1945 applyToLibraryFieldAttribute( aAttributeVal.AttributeLocation, symDefOrigin,
1946 attrField );
1947 }
1948 else if( attrIsNew )
1949 {
1950 attrField->SetVisible( false );
1951 applyTextSettings( attrField, wxT( "TC1" ), ALIGNMENT::NO_ALIGNMENT,
1952 JUSTIFICATION::LEFT, false, true );
1953 }
1954 };
1955
1956 // Load all attributes in the Part Definition
1957 for( auto& [attrId, attrVal] : aCadstarPart.Definition.AttributeValues )
1958 loadLibraryField( attrVal );
1959
1960 // Load all attributes in the Part itself.
1961 for( auto& [attrId, attrVal] : aCadstarPart.AttributeValues )
1962 loadLibraryField( attrVal );
1963
1964 setFootprintOnSymbol( tempSymbol, footprintRefName, footprintAlternateName );
1965
1966 if( aCadstarPart.Definition.HidePinNames )
1967 {
1968 tempSymbol->SetShowPinNames( false );
1969 tempSymbol->SetShowPinNumbers( false );
1970 }
1971
1972 // Update aSymbol just to keep lint happy.
1973 aSymbol = tempSymbol.release();
1974}
1975
1976
1977void CADSTAR_SCH_ARCHIVE_LOADER::setFootprintOnSymbol( std::unique_ptr<LIB_SYMBOL>& aKiCadSymbol,
1978 const wxString& aFootprintName,
1979 const wxString& aFootprintAlternate )
1980{
1981 wxString fpNameInLibrary = generateLibName( aFootprintName, aFootprintAlternate );
1982
1983 if( !fpNameInLibrary.IsEmpty() )
1984 {
1985 wxArrayString fpFilters;
1986 fpFilters.Add( aFootprintName ); // In cadstar one footprint has several "alternates"
1987
1988 if( !aFootprintAlternate.IsEmpty() )
1989 fpFilters.Add( fpNameInLibrary );
1990
1991 aKiCadSymbol->SetFPFilters( fpFilters );
1992
1993 LIB_ID libID( m_footprintLibName, fpNameInLibrary );
1994 aKiCadSymbol->GetFootprintField().SetText( libID.Format() );
1995 }
1996}
1997
1998
1999void CADSTAR_SCH_ARCHIVE_LOADER::loadLibrarySymbolShapeVertices( const std::vector<VERTEX>& aCadstarVertices,
2000 const VECTOR2I& aSymbolOrigin,
2001 LIB_SYMBOL* aSymbol,
2002 int aGateNumber,
2003 int aLineThickness )
2004{
2005 const VERTEX* prev = &aCadstarVertices.at( 0 );
2006 const VERTEX* cur;
2007
2008 wxASSERT_MSG( prev->Type == VERTEX_TYPE::POINT, "First vertex should always be a point." );
2009
2010 for( size_t i = 1; i < aCadstarVertices.size(); i++ )
2011 {
2012 cur = &aCadstarVertices.at( i );
2013
2014 SCH_SHAPE* shape = nullptr;
2015 bool cw = false;
2016 VECTOR2I startPoint = getKiCadLibraryPoint( prev->End, aSymbolOrigin );
2017 VECTOR2I endPoint = getKiCadLibraryPoint( cur->End, aSymbolOrigin );
2018 VECTOR2I centerPoint;
2019
2022 {
2023 centerPoint = ( startPoint + endPoint ) / 2;
2024 }
2025 else
2026 {
2027 centerPoint = getKiCadLibraryPoint( cur->Center, aSymbolOrigin );
2028 }
2029
2030
2031 switch( cur->Type )
2032 {
2033 case VERTEX_TYPE::POINT:
2034 shape = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2035 shape->AddPoint( startPoint );
2036 shape->AddPoint( endPoint );
2037 break;
2038
2041 cw = true;
2043
2046 shape = new SCH_SHAPE( SHAPE_T::ARC, LAYER_DEVICE );
2047
2048 shape->SetPosition( centerPoint );
2049
2050 if( cw )
2051 {
2052 shape->SetStart( endPoint );
2053 shape->SetEnd( startPoint );
2054 }
2055 else
2056 {
2057 shape->SetStart( startPoint );
2058 shape->SetEnd( endPoint );
2059 }
2060
2061 break;
2062 }
2063
2064 shape->SetUnit( aGateNumber );
2065 shape->SetStroke( STROKE_PARAMS( aLineThickness, LINE_STYLE::SOLID ) );
2066 aSymbol->AddDrawItem( shape, false );
2067
2068 prev = cur;
2069 }
2070
2071 aSymbol->GetDrawItems().sort();
2072}
2073
2074
2076 const VECTOR2I& aSymbolOrigin,
2077 SCH_FIELD* aKiCadField )
2078{
2079 aKiCadField->SetTextPos( getKiCadLibraryPoint( aCadstarAttrLoc.Position, aSymbolOrigin ) );
2080
2081 applyTextSettings( aKiCadField, aCadstarAttrLoc.TextCodeID, aCadstarAttrLoc.Alignment,
2082 aCadstarAttrLoc.Justification, aCadstarAttrLoc.OrientAngle,
2083 aCadstarAttrLoc.Mirror );
2084}
2085
2086
2088 const LIB_SYMBOL& aKiCadPart,
2089 EDA_ANGLE& aComponentOrientation )
2090{
2091 wxString libName = CreateLibName( m_footprintLibName, m_rootSheet );
2092
2093 LIB_ID libId;
2094 libId.SetLibItemName( aKiCadPart.GetName() );
2095 libId.SetLibNickname( libName );
2096
2097 int unit = getKiCadUnitNumberFromGate( aCadstarSymbol.GateID );
2098
2099 SCH_SHEET_PATH sheetpath;
2100 SCH_SHEET* kiSheet = m_sheetMap.at( aCadstarSymbol.LayerID );
2101 m_rootSheet->LocatePathOfScreen( kiSheet->GetScreen(), &sheetpath );
2102
2103 SCH_SYMBOL* symbol = new SCH_SYMBOL( aKiCadPart, libId, &sheetpath, unit );
2104
2105 if( aCadstarSymbol.IsComponent )
2106 symbol->SetRef( &sheetpath, aCadstarSymbol.ComponentRef.Designator );
2107
2108 symbol->SetPosition( getKiCadPoint( aCadstarSymbol.Origin ) );
2109
2110 EDA_ANGLE compAngle = getAngle( aCadstarSymbol.OrientAngle );
2111 int compOrientation = 0;
2112
2113 if( aCadstarSymbol.Mirror )
2114 {
2115 compAngle = -compAngle;
2116 compOrientation += SYMBOL_ORIENTATION_T::SYM_MIRROR_Y;
2117 }
2118
2119 compOrientation += getComponentOrientation( compAngle, aComponentOrientation );
2120 EDA_ANGLE test1( compAngle );
2121 EDA_ANGLE test2( aComponentOrientation );
2122
2123 if( test1.Normalize180() != test2.Normalize180() )
2124 {
2125 m_reporter->Report( wxString::Format( _( "Symbol '%s' is rotated by an angle of %.1f "
2126 "degrees in the original CADSTAR design but "
2127 "KiCad only supports rotation angles multiples "
2128 "of 90 degrees. The connecting wires will need "
2129 "manual fixing." ),
2130 aCadstarSymbol.ComponentRef.Designator,
2131 compAngle.AsDegrees() ),
2133 }
2134
2135 symbol->SetOrientation( compOrientation );
2136
2137 if( m_sheetMap.find( aCadstarSymbol.LayerID ) == m_sheetMap.end() )
2138 {
2139 m_reporter->Report( wxString::Format( _( "Symbol '%s' references sheet ID '%s' which does "
2140 "not exist in the design. The symbol was not "
2141 "loaded." ),
2142 aCadstarSymbol.ComponentRef.Designator,
2143 aCadstarSymbol.LayerID ),
2145
2146 delete symbol;
2147 return nullptr;
2148 }
2149
2150 wxString gate = ( aCadstarSymbol.GateID.IsEmpty() ) ? wxString( wxT( "A" ) ) : aCadstarSymbol.GateID;
2151 wxString partGateIndex = aCadstarSymbol.PartRef.RefID + gate;
2152
2153 //Handle pin swaps
2154 if( m_pinNumsMap.find( partGateIndex ) != m_pinNumsMap.end() )
2155 {
2156 TERMINAL_TO_PINNUM_MAP termNumMap = m_pinNumsMap.at( partGateIndex );
2157
2158 std::map<wxString, SCH_PIN*> pinNumToLibPinMap;
2159
2160 for( auto& term : termNumMap )
2161 {
2162 wxString pinNum = term.second;
2163 pinNumToLibPinMap.insert( { pinNum,
2164 symbol->GetLibSymbolRef()->GetPin( term.second ) } );
2165 }
2166
2167 auto replacePinNumber =
2168 [&]( wxString aOldPinNum, wxString aNewPinNum )
2169 {
2170 if( aOldPinNum == aNewPinNum )
2171 return;
2172
2173 SCH_PIN* libpin = pinNumToLibPinMap.at( aOldPinNum );
2174 libpin->SetNumber( HandleTextOverbar( aNewPinNum ) );
2175 };
2176
2177 //Older versions of Cadstar used pin numbers
2178 for( auto& pinPair : aCadstarSymbol.PinNumbers )
2179 {
2180 SYMBOL::PIN_NUM pin = pinPair.second;
2181
2182 replacePinNumber( termNumMap.at( pin.TerminalID ),
2183 wxString::Format( "%ld", pin.PinNum ) );
2184 }
2185
2186 //Newer versions of Cadstar use pin names
2187 for( auto& pinPair : aCadstarSymbol.PinNames )
2188 {
2189 SYMPINNAME_LABEL pin = pinPair.second;
2190 replacePinNumber( termNumMap.at( pin.TerminalID ), pin.NameOrLabel );
2191 }
2192
2193 symbol->UpdatePins();
2194 }
2195
2196 kiSheet->GetScreen()->Append( symbol );
2197
2198 return symbol;
2199}
2200
2201
2203 const EDA_ANGLE& aComponentOrientation,
2204 bool aIsMirrored,
2205 SCH_FIELD* aKiCadField )
2206{
2207 aKiCadField->SetPosition( getKiCadPoint( aCadstarAttrLoc.Position ) );
2208 aKiCadField->SetVisible( true );
2209
2210 ALIGNMENT alignment = aCadstarAttrLoc.Alignment;
2211 EDA_ANGLE textAngle = getAngle( aCadstarAttrLoc.OrientAngle );
2212
2213 if( aIsMirrored )
2214 {
2215 // We need to change the aligment when the symbol is mirrored based on the text orientation
2216 // To ensure the anchor point is the same in KiCad.
2217
2218 int textIsVertical = KiROUND( textAngle.AsDegrees() / 90.0 ) % 2;
2219
2220 if( textIsVertical )
2221 alignment = rotate180( alignment );
2222
2223 alignment = mirrorX( alignment );
2224 }
2225
2226 applyTextSettings( aKiCadField, aCadstarAttrLoc.TextCodeID, alignment,
2227 aCadstarAttrLoc.Justification,
2228 getCadstarAngle( textAngle - aComponentOrientation ),
2229 aCadstarAttrLoc.Mirror );
2230}
2231
2232
2234 EDA_ANGLE& aReturnedOrientation )
2235{
2236 int compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_0;
2237
2238 EDA_ANGLE oDeg = aOrientAngle;
2239 oDeg.Normalize180();
2240
2241 if( oDeg >= -ANGLE_45 && oDeg <= ANGLE_45 )
2242 {
2243 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_0;
2244 aReturnedOrientation = ANGLE_0;
2245 }
2246 else if( oDeg >= ANGLE_45 && oDeg <= ANGLE_135 )
2247 {
2248 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_90;
2249 aReturnedOrientation = ANGLE_90;
2250 }
2251 else if( oDeg >= ANGLE_135 || oDeg <= -ANGLE_135 )
2252 {
2253 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_180;
2254 aReturnedOrientation = ANGLE_180;
2255 }
2256 else
2257 {
2258 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_270;
2259 aReturnedOrientation = ANGLE_270;
2260 }
2261
2262 return compOrientation;
2263}
2264
2265
2268 const NETELEMENT_ID& aNetElementID )
2269{
2270 // clang-format off
2271 auto logUnknownNetElementError =
2272 [&]()
2273 {
2274 m_reporter->Report( wxString::Format( _( "Net %s references unknown net element %s. "
2275 "The net was not properly loaded and may "
2276 "require manual fixing." ),
2277 getNetName( aNet ),
2278 aNetElementID ),
2280
2281 return POINT();
2282 };
2283 // clang-format on
2284
2285 if( aNetElementID.Contains( "J" ) ) // Junction
2286 {
2287 if( aNet.Junctions.find( aNetElementID ) == aNet.Junctions.end() )
2288 return logUnknownNetElementError();
2289
2290 return aNet.Junctions.at( aNetElementID ).Location;
2291 }
2292 else if( aNetElementID.Contains( "P" ) ) // Terminal/Pin of a symbol
2293 {
2294 if( aNet.Terminals.find( aNetElementID ) == aNet.Terminals.end() )
2295 return logUnknownNetElementError();
2296
2297 SYMBOL_ID symid = aNet.Terminals.at( aNetElementID ).SymbolID;
2298 TERMINAL_ID termid = aNet.Terminals.at( aNetElementID ).TerminalID;
2299
2300 if( Schematic.Symbols.find( symid ) == Schematic.Symbols.end() )
2301 return logUnknownNetElementError();
2302
2303 SYMBOL sym = Schematic.Symbols.at( symid );
2304 SYMDEF_ID symdefid = sym.SymdefID;
2305 VECTOR2I symbolOrigin = sym.Origin;
2306
2307 if( Library.SymbolDefinitions.find( symdefid ) == Library.SymbolDefinitions.end() )
2308 return logUnknownNetElementError();
2309
2310 VECTOR2I libpinPosition =
2311 Library.SymbolDefinitions.at( symdefid ).Terminals.at( termid ).Position;
2312 VECTOR2I libOrigin = Library.SymbolDefinitions.at( symdefid ).Origin;
2313
2314 VECTOR2I pinOffset = libpinPosition - libOrigin;
2315 pinOffset.x = ( pinOffset.x * sym.ScaleRatioNumerator ) / sym.ScaleRatioDenominator;
2316 pinOffset.y = ( pinOffset.y * sym.ScaleRatioNumerator ) / sym.ScaleRatioDenominator;
2317
2318 VECTOR2I pinPosition = symbolOrigin + pinOffset;
2319 EDA_ANGLE compAngle = getAngle( sym.OrientAngle );
2320
2321 if( sym.Mirror )
2322 pinPosition.x = ( 2 * symbolOrigin.x ) - pinPosition.x;
2323
2324 EDA_ANGLE adjustedOrientation;
2325 getComponentOrientation( compAngle, adjustedOrientation );
2326
2327 RotatePoint( pinPosition, symbolOrigin, -adjustedOrientation );
2328
2329 POINT retval;
2330 retval.x = pinPosition.x;
2331 retval.y = pinPosition.y;
2332
2333 return retval;
2334 }
2335 else if( aNetElementID.Contains( "BT" ) ) // Bus Terminal
2336 {
2337 if( aNet.BusTerminals.find( aNetElementID ) == aNet.BusTerminals.end() )
2338 return logUnknownNetElementError();
2339
2340 return aNet.BusTerminals.at( aNetElementID ).SecondPoint;
2341 }
2342 else if( aNetElementID.Contains( "BLKT" ) ) // Block Terminal (sheet hierarchy connection)
2343 {
2344 if( aNet.BlockTerminals.find( aNetElementID ) == aNet.BlockTerminals.end() )
2345 return logUnknownNetElementError();
2346
2347 BLOCK_ID blockid = aNet.BlockTerminals.at( aNetElementID ).BlockID;
2348 TERMINAL_ID termid = aNet.BlockTerminals.at( aNetElementID ).TerminalID;
2349
2350 if( Schematic.Blocks.find( blockid ) == Schematic.Blocks.end() )
2351 return logUnknownNetElementError();
2352
2353 return Schematic.Blocks.at( blockid ).Terminals.at( termid ).Position;
2354 }
2355 else if( aNetElementID.Contains( "D" ) ) // Dangler
2356 {
2357 if( aNet.Danglers.find( aNetElementID ) == aNet.Danglers.end() )
2358 return logUnknownNetElementError();
2359
2360 return aNet.Danglers.at( aNetElementID ).Position;
2361 }
2362 else
2363 {
2364 return logUnknownNetElementError();
2365 }
2366}
2367
2368
2370{
2371 wxString netname = aNet.Name;
2372
2373 if( netname.IsEmpty() )
2374 netname = wxString::Format( "$%ld", aNet.SignalNum );
2375
2376 return netname;
2377}
2378
2379
2380void CADSTAR_SCH_ARCHIVE_LOADER::loadShapeVertices( const std::vector<VERTEX>& aCadstarVertices,
2381 LINECODE_ID aCadstarLineCodeID,
2382 LAYER_ID aCadstarSheetID,
2383 SCH_LAYER_ID aKiCadSchLayerID,
2384 const VECTOR2I& aMoveVector,
2385 const EDA_ANGLE& aRotation,
2386 const double& aScalingFactor,
2387 const VECTOR2I& aTransformCentre,
2388 const bool& aMirrorInvert )
2389{
2390 int lineWidth = KiROUND( getLineThickness( aCadstarLineCodeID ) * aScalingFactor );
2391 LINE_STYLE lineStyle = getLineStyle( aCadstarLineCodeID );
2392
2393 const VERTEX* prev = &aCadstarVertices.at( 0 );
2394 const VERTEX* cur;
2395
2396 wxASSERT_MSG( prev->Type == VERTEX_TYPE::POINT,
2397 "First vertex should always be a point vertex" );
2398
2399 auto pointTransform =
2400 [&]( const VECTOR2I& aV )
2401 {
2402 return applyTransform( getKiCadPoint( aV ), aMoveVector, aRotation,
2403 aScalingFactor, aTransformCentre, aMirrorInvert );
2404 };
2405
2406 for( size_t ii = 1; ii < aCadstarVertices.size(); ii++ )
2407 {
2408 cur = &aCadstarVertices.at( ii );
2409
2410 VECTOR2I transformedStartPoint = pointTransform( prev->End );
2411 VECTOR2I transformedEndPoint = pointTransform( cur->End );
2412
2413 switch( cur->Type )
2414 {
2419 {
2420 SHAPE_ARC tempArc = cur->BuildArc( transformedStartPoint, pointTransform );
2421
2422 SCH_SHAPE* arcShape = new SCH_SHAPE( SHAPE_T::ARC, LAYER_NOTES, lineWidth );
2423 arcShape->SetArcGeometry( tempArc.GetP0(), tempArc.GetArcMid(), tempArc.GetP1() );
2424
2425 loadItemOntoKiCadSheet( aCadstarSheetID, arcShape );
2426 break;
2427 }
2428
2429 case VERTEX_TYPE::POINT:
2430 {
2431 SCH_LINE* segment = new SCH_LINE();
2432
2433 segment->SetLayer( aKiCadSchLayerID );
2434 segment->SetLineWidth( lineWidth );
2435 segment->SetLineStyle( lineStyle );
2436
2437 segment->SetStartPoint( transformedStartPoint );
2438 segment->SetEndPoint( transformedEndPoint );
2439
2440 loadItemOntoKiCadSheet( aCadstarSheetID, segment );
2441 break;
2442 }
2443
2444 default:
2445 wxFAIL_MSG( "Unknown CADSTAR Vertex type" );
2446 }
2447
2448 prev = cur;
2449 }
2450}
2451
2452
2454 const LAYER_ID& aCadstarSheetIDOverride,
2455 SCH_LAYER_ID aKiCadSchLayerID,
2456 const VECTOR2I& aMoveVector,
2457 const EDA_ANGLE& aRotation,
2458 const double& aScalingFactor,
2459 const VECTOR2I& aTransformCentre,
2460 const bool& aMirrorInvert )
2461{
2462 loadShapeVertices( aCadstarFigure.Shape.Vertices, aCadstarFigure.LineCodeID,
2463 aCadstarSheetIDOverride, aKiCadSchLayerID, aMoveVector, aRotation,
2464 aScalingFactor, aTransformCentre, aMirrorInvert );
2465
2466 for( const CUTOUT& cutout : aCadstarFigure.Shape.Cutouts )
2467 {
2468 loadShapeVertices( cutout.Vertices, aCadstarFigure.LineCodeID, aCadstarSheetIDOverride,
2469 aKiCadSchLayerID, aMoveVector, aRotation, aScalingFactor,
2470 aTransformCentre, aMirrorInvert );
2471 }
2472}
2473
2474
2476 const VECTOR2I& aPosition,
2477 const VECTOR2I& aSheetSize,
2478 const SCH_SHEET_PATH& aParentSheet )
2479{
2480 wxCHECK_MSG( m_sheetMap.find( aCadstarSheetID ) == m_sheetMap.end(), ,
2481 "Sheet already loaded!" );
2482
2483 SCH_SHEET* sheet = new SCH_SHEET(
2484 /* aParent */ aParentSheet.Last(),
2485 /* aPosition */ aPosition,
2486 /* aSize */ VECTOR2I( aSheetSize ) );
2487 SCH_SCREEN* screen = new SCH_SCREEN( m_schematic );
2488 SCH_SHEET_PATH instance( aParentSheet );
2489
2490 sheet->SetScreen( screen );
2491
2492 wxString name = Sheets.SheetNames.at( aCadstarSheetID );
2493
2494 SCH_FIELD& sheetNameField = sheet->GetFields()[SHEETNAME];
2495 SCH_FIELD& filenameField = sheet->GetFields()[SHEETFILENAME];
2496
2497 sheetNameField.SetText( name );
2498
2499 int sheetNum = getSheetNumber( aCadstarSheetID );
2500 wxString loadedFilename = wxFileName( Filename ).GetName();
2501 std::string filename = wxString::Format( "%s_%02d", loadedFilename, sheetNum ).ToStdString();
2502
2503 ReplaceIllegalFileNameChars( &filename );
2504 filename += wxT( "." ) + wxString( FILEEXT::KiCadSchematicFileExtension );
2505
2506 filenameField.SetText( filename );
2507
2508 wxFileName fn( m_schematic->Prj().GetProjectPath() + filename );
2509 sheet->GetScreen()->SetFileName( fn.GetFullPath() );
2510 aParentSheet.Last()->GetScreen()->Append( sheet );
2511 instance.push_back( sheet );
2512
2513 wxString pageNumStr = wxString::Format( "%d", getSheetNumber( aCadstarSheetID ) );
2514 instance.SetPageNumber( pageNumStr );
2515
2516 sheet->AutoplaceFields( /* aScreen */ nullptr, /* aManual */ false );
2517
2518 m_sheetMap.insert( { aCadstarSheetID, sheet } );
2519
2520 loadChildSheets( aCadstarSheetID, instance );
2521}
2522
2523
2525 const SCH_SHEET_PATH& aSheet )
2526{
2527 wxCHECK_MSG( m_sheetMap.find( aCadstarSheetID ) != m_sheetMap.end(), ,
2528 "FIXME! Parent sheet should be loaded before attempting to load subsheets" );
2529
2530 for( std::pair<BLOCK_ID, BLOCK> blockPair : Schematic.Blocks )
2531 {
2532 BLOCK& block = blockPair.second;
2533
2534 if( block.LayerID == aCadstarSheetID && block.Type == BLOCK::TYPE::CHILD )
2535 {
2536 if( block.AssocLayerID == wxT( "NO_LINK" ) )
2537 {
2538 if( block.Figures.size() > 0 )
2539 {
2540 m_reporter->Report( wxString::Format( _( "The block ID %s (Block name: '%s') "
2541 "is drawn on sheet '%s' but is not "
2542 "linked to another sheet in the "
2543 "design. KiCad requires all sheet "
2544 "symbols to be associated to a sheet, "
2545 "so the block was not loaded." ),
2546 block.ID, block.Name,
2547 Sheets.SheetNames.at( aCadstarSheetID ) ),
2549 }
2550
2551 continue;
2552 }
2553
2554 // In KiCad you can only draw rectangular shapes whereas in Cadstar arbitrary shapes
2555 // are allowed. We will calculate the extents of the Cadstar shape and draw a rectangle
2556
2557 std::pair<VECTOR2I, VECTOR2I> blockExtents;
2558
2559 if( block.Figures.size() > 0 )
2560 {
2561 blockExtents = getFigureExtentsKiCad( block.Figures.begin()->second );
2562 }
2563 else
2564 {
2565 THROW_IO_ERROR( wxString::Format( _( "The CADSTAR schematic might be corrupt: "
2566 "Block %s references a child sheet but has no "
2567 "Figure defined." ),
2568 block.ID ) );
2569 }
2570
2571 loadSheetAndChildSheets( block.AssocLayerID, blockExtents.first, blockExtents.second,
2572 aSheet );
2573
2574 // Hide all KiCad sheet properties (sheet name/filename is not applicable in CADSTAR)
2575 SCH_SHEET* loadedSheet = m_sheetMap.at( block.AssocLayerID );
2576 SCH_FIELDS fields = loadedSheet->GetFields();
2577
2578 for( SCH_FIELD& field : fields )
2579 {
2580 field.SetVisible( false );
2581 }
2582
2583 if( block.HasBlockLabel )
2584 {
2585 //@todo use below code when KiCad supports multi-line fields
2586 /*
2587 // Add the block label as a separate field
2588 SCH_FIELD blockNameField( getKiCadPoint( block.BlockLabel.Position ), 2,
2589 loadedSheet, wxString( "Block name" ) );
2590 blockNameField.SetText( block.Name );
2591 blockNameField.SetVisible( true );
2592
2593 applyTextSettings( &blockNameField,
2594 block.BlockLabel.TextCodeID,
2595 block.BlockLabel.Alignment,
2596 block.BlockLabel.Justification,
2597 block.BlockLabel.OrientAngle,
2598 block.BlockLabel.Mirror );
2599
2600 fields.push_back( blockNameField );*/
2601
2602 // For now as as a text item (supports multi-line properly)
2603 SCH_TEXT* kiTxt = new SCH_TEXT();
2604
2605 kiTxt->SetParent( m_schematic );
2606 kiTxt->SetPosition( getKiCadPoint( block.BlockLabel.Position ) );
2607 kiTxt->SetText( block.Name );
2608
2611 block.BlockLabel.Mirror );
2612
2613 loadItemOntoKiCadSheet( aCadstarSheetID, kiTxt );
2614 }
2615
2616 loadedSheet->SetFields( fields );
2617 }
2618 }
2619}
2620
2621
2622std::vector<CADSTAR_SCH_ARCHIVE_LOADER::LAYER_ID> CADSTAR_SCH_ARCHIVE_LOADER::findOrphanSheets()
2623{
2624 std::vector<LAYER_ID> childSheets, orphanSheets;
2625
2626 //Find all sheets that are child of another
2627 for( std::pair<BLOCK_ID, BLOCK> blockPair : Schematic.Blocks )
2628 {
2629 BLOCK& block = blockPair.second;
2630 LAYER_ID& assocSheetID = block.AssocLayerID;
2631
2632 if( block.Type == BLOCK::TYPE::CHILD )
2633 childSheets.push_back( assocSheetID );
2634 }
2635
2636 //Add sheets that do not have a parent
2637 for( const LAYER_ID& sheetID : Sheets.SheetOrder )
2638 {
2639 if( std::find( childSheets.begin(), childSheets.end(), sheetID ) == childSheets.end() )
2640 orphanSheets.push_back( sheetID );
2641 }
2642
2643 return orphanSheets;
2644}
2645
2646
2648{
2649 int i = 1;
2650
2651 for( const LAYER_ID& sheetID : Sheets.SheetOrder )
2652 {
2653 if( sheetID == aCadstarSheetID )
2654 return i;
2655
2656 ++i;
2657 }
2658
2659 return -1;
2660}
2661
2662
2664 SCH_ITEM* aItem )
2665{
2666 wxCHECK_MSG( aItem, /*void*/, wxT( "aItem is null" ) );
2667
2668 if( aCadstarSheetID == "ALL_SHEETS" )
2669 {
2670 SCH_ITEM* duplicateItem = nullptr;
2671
2672 for( std::pair<LAYER_ID, SHEET_NAME> sheetPair : Sheets.SheetNames )
2673 {
2674 LAYER_ID sheetID = sheetPair.first;
2675 duplicateItem = aItem->Duplicate();
2676 m_sheetMap.at( sheetID )->GetScreen()->Append( aItem->Duplicate() );
2677 }
2678
2679 //Get rid of the extra copy:
2680 delete aItem;
2681 aItem = duplicateItem;
2682 }
2683 else if( aCadstarSheetID == "NO_SHEET" )
2684 {
2685 wxFAIL_MSG( wxT( "Trying to add an item to NO_SHEET? This might be a documentation symbol." ) );
2686 }
2687 else
2688 {
2689 if( m_sheetMap.find( aCadstarSheetID ) != m_sheetMap.end() )
2690 {
2691 m_sheetMap.at( aCadstarSheetID )->GetScreen()->Append( aItem );
2692 }
2693 else
2694 {
2695 delete aItem;
2696 wxFAIL_MSG( wxT( "Unknown Sheet ID." ) );
2697 }
2698 }
2699}
2700
2701
2704 const wxString& aSymDefAlternate )
2705{
2706 if( m_SymDefNamesCache.size() != Library.SymbolDefinitions.size() )
2707 {
2708 // Re-initialise
2709 m_SymDefNamesCache.clear();
2711
2712 // Create a lower case cache to avoid searching each time
2713 for( auto& [id, symdef] : Library.SymbolDefinitions )
2714 {
2715 wxString refKey = symdef.ReferenceName.Lower();
2716 wxString altKey = symdef.Alternate.Lower();
2717
2718 m_SymDefNamesCache[{ refKey, altKey }] = id;
2719
2720 // Secondary cache to find symbols just by the Name (e.g. if the alternate
2721 // does not exist, we still want to return a symbo - the same behaviour
2722 // as CADSTAR
2723
2724 if( !m_DefaultSymDefNamesCache.count( refKey ) )
2725 {
2726 m_DefaultSymDefNamesCache.insert( { refKey, id } );
2727 }
2728 else if( altKey.IsEmpty() )
2729 {
2730 // Always use the empty alternate if it exists
2731 m_DefaultSymDefNamesCache[refKey] = id;
2732 }
2733 }
2734 }
2735
2736 wxString refKeyToFind = aSymdefName.Lower();
2737 wxString altKeyToFind = aSymDefAlternate.Lower();
2738
2739 if( m_SymDefNamesCache.count( { refKeyToFind, altKeyToFind } ) )
2740 {
2741 return m_SymDefNamesCache[{ refKeyToFind, altKeyToFind }];
2742 }
2743 else if( m_DefaultSymDefNamesCache.count( refKeyToFind ) )
2744 {
2745 return m_DefaultSymDefNamesCache[refKeyToFind];
2746 }
2747
2748 return SYMDEF_ID();
2749}
2750
2751
2753{
2754 // Use CADSTAR visibility settings to determine if an attribute is visible
2755 if( AttrColors.AttributeColors.find( aCadstarAttributeID ) != AttrColors.AttributeColors.end() )
2756 return AttrColors.AttributeColors.at( aCadstarAttributeID ).IsVisible;
2757
2758 return false; // If there is no visibility setting, assume not displayed
2759}
2760
2761
2763{
2764 wxCHECK( Assignments.Codedefs.LineCodes.find( aCadstarLineCodeID )
2767
2768 return getKiCadLength( Assignments.Codedefs.LineCodes.at( aCadstarLineCodeID ).Width );
2769}
2770
2771
2773{
2774 wxCHECK( Assignments.Codedefs.LineCodes.find( aCadstarLineCodeID )
2776 LINE_STYLE::SOLID );
2777
2778 // clang-format off
2779 switch( Assignments.Codedefs.LineCodes.at( aCadstarLineCodeID ).Style )
2780 {
2781 case LINESTYLE::DASH: return LINE_STYLE::DASH;
2782 case LINESTYLE::DASHDOT: return LINE_STYLE::DASHDOT;
2783 case LINESTYLE::DASHDOTDOT: return LINE_STYLE::DASHDOT; //TODO: update in future
2784 case LINESTYLE::DOT: return LINE_STYLE::DOT;
2785 case LINESTYLE::SOLID: return LINE_STYLE::SOLID;
2786 default: return LINE_STYLE::DEFAULT;
2787 }
2788 // clang-format on
2789}
2790
2791
2794{
2795 wxCHECK( Assignments.Codedefs.TextCodes.find( aCadstarTextCodeID )
2797 TEXTCODE() );
2798
2799 return Assignments.Codedefs.TextCodes.at( aCadstarTextCodeID );
2800}
2801
2802
2804{
2805 TEXTCODE txtCode = getTextCode( aCadstarTextCodeID );
2806
2807 return KiROUND( (double) getKiCadLength( txtCode.Height ) * TXT_HEIGHT_RATIO );
2808}
2809
2810
2812{
2813 wxCHECK( Assignments.Codedefs.AttributeNames.find( aCadstarAttributeID )
2815 aCadstarAttributeID );
2816
2817 return Assignments.Codedefs.AttributeNames.at( aCadstarAttributeID ).Name;
2818}
2819
2820
2823{
2824 wxCHECK( Parts.PartDefinitions.find( aCadstarPartID ) != Parts.PartDefinitions.end(), PART() );
2825
2826 return Parts.PartDefinitions.at( aCadstarPartID );
2827}
2828
2829
2832{
2833 wxCHECK( Assignments.Codedefs.RouteCodes.find( aCadstarRouteCodeID )
2835 ROUTECODE() );
2836
2837 return Assignments.Codedefs.RouteCodes.at( aCadstarRouteCodeID );
2838}
2839
2840
2841CADSTAR_SCH_ARCHIVE_LOADER::PART::DEFINITION::PIN
2843 const TERMINAL_ID& aTerminalID )
2844{
2845 for( std::pair<PART_DEFINITION_PIN_ID, PART::DEFINITION::PIN> pinPair :
2846 aCadstarPart.Definition.Pins )
2847 {
2848 PART::DEFINITION::PIN partPin = pinPair.second;
2849
2850 if( partPin.TerminalGate == aGateID && partPin.TerminalPin == aTerminalID )
2851 return partPin;
2852 }
2853
2854 return PART::DEFINITION::PIN();
2855}
2856
2857
2859{
2860 switch( aPinType )
2861 {
2862 case CADSTAR_PIN_TYPE::UNCOMMITTED: return ELECTRICAL_PINTYPE::PT_PASSIVE;
2863 case CADSTAR_PIN_TYPE::INPUT: return ELECTRICAL_PINTYPE::PT_INPUT;
2864 case CADSTAR_PIN_TYPE::OUTPUT_OR: return ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR;
2865 case CADSTAR_PIN_TYPE::OUTPUT_NOT_OR: return ELECTRICAL_PINTYPE::PT_OUTPUT;
2866 case CADSTAR_PIN_TYPE::OUTPUT_NOT_NORM_OR: return ELECTRICAL_PINTYPE::PT_OUTPUT;
2867 case CADSTAR_PIN_TYPE::POWER: return ELECTRICAL_PINTYPE::PT_POWER_IN;
2868 case CADSTAR_PIN_TYPE::GROUND: return ELECTRICAL_PINTYPE::PT_POWER_IN;
2869 case CADSTAR_PIN_TYPE::TRISTATE_BIDIR: return ELECTRICAL_PINTYPE::PT_BIDI;
2870 case CADSTAR_PIN_TYPE::TRISTATE_INPUT: return ELECTRICAL_PINTYPE::PT_INPUT;
2871 case CADSTAR_PIN_TYPE::TRISTATE_DRIVER: return ELECTRICAL_PINTYPE::PT_OUTPUT;
2872 }
2873
2874 return ELECTRICAL_PINTYPE::PT_UNSPECIFIED;
2875}
2876
2878{
2879 if( aCadstarGateID.IsEmpty() )
2880 return 1;
2881
2882 return (int) aCadstarGateID.Upper().GetChar( 0 ) - (int) wxUniChar( 'A' ) + 1;
2883}
2884
2885
2886SPIN_STYLE CADSTAR_SCH_ARCHIVE_LOADER::getSpinStyle( const long long& aCadstarOrientation,
2887 bool aMirror )
2888{
2889 EDA_ANGLE orientation = getAngle( aCadstarOrientation );
2890 SPIN_STYLE spinStyle = getSpinStyle( orientation );
2891
2892 if( aMirror )
2893 {
2894 spinStyle = spinStyle.RotateCCW();
2895 spinStyle = spinStyle.RotateCCW();
2896 }
2897
2898 return spinStyle;
2899}
2900
2901
2903{
2904 SPIN_STYLE spinStyle = SPIN_STYLE::LEFT;
2905
2906 EDA_ANGLE oDeg = aOrientation;
2907 oDeg.Normalize180();
2908
2909 if( oDeg >= -ANGLE_45 && oDeg <= ANGLE_45 )
2910 spinStyle = SPIN_STYLE::RIGHT; // 0deg
2911 else if( oDeg >= ANGLE_45 && oDeg <= ANGLE_135 )
2912 spinStyle = SPIN_STYLE::UP; // 90deg
2913 else if( oDeg >= ANGLE_135 || oDeg <= -ANGLE_135 )
2914 spinStyle = SPIN_STYLE::LEFT; // 180deg
2915 else
2916 spinStyle = SPIN_STYLE::BOTTOM; // 270deg
2917
2918 return spinStyle;
2919}
2920
2921
2924{
2925 switch( aCadstarAlignment )
2926 {
2927 // Change left to right:
2932
2933 //Change right to left:
2937
2938 // Center alignment does not mirror:
2941 case ALIGNMENT::TOPCENTER: return aCadstarAlignment;
2942
2943 // Shouldn't be here
2944 default: wxFAIL_MSG( "Unknown Cadstar Alignment" ); return aCadstarAlignment;
2945 }
2946}
2947
2948
2951{
2952 switch( aCadstarAlignment )
2953 {
2964
2965 // Shouldn't be here
2966 default: wxFAIL_MSG( "Unknown Cadstar Alignment" ); return aCadstarAlignment;
2967 }
2968}
2969
2970
2972 const TEXTCODE_ID& aCadstarTextCodeID )
2973{
2974 // Ensure we have no Cadstar overbar characters
2975 wxString escapedText = HandleTextOverbar( aKiCadTextItem->GetText() );
2976 aKiCadTextItem->SetText( escapedText );
2977
2978 if( !Assignments.Codedefs.TextCodes.count( aCadstarTextCodeID ) )
2979 return;
2980
2981 TEXTCODE textCode = getTextCode( aCadstarTextCodeID );
2982 int textHeight = KiROUND( (double) getKiCadLength( textCode.Height ) * TXT_HEIGHT_RATIO );
2983 int textWidth = getKiCadLength( textCode.Width );
2984
2985 // The width is zero for all non-cadstar fonts. Using a width equal to 2/3 the height seems
2986 // to work well for most fonts.
2987 if( textWidth == 0 )
2988 textWidth = getKiCadLength( 2LL * textCode.Height / 3LL );
2989
2990 aKiCadTextItem->SetTextWidth( textWidth );
2991 aKiCadTextItem->SetTextHeight( textHeight );
2992
2993#if 0
2994 // EEschema currently supports only normal vs bold for text thickness.
2995 aKiCadTextItem->SetTextThickness( getKiCadLength( textCode.LineWidth ) );
2996#endif
2997
2998 // Must come after SetTextSize()
2999 aKiCadTextItem->SetBold( textCode.Font.Modifier1 == FONT_BOLD );
3000 aKiCadTextItem->SetItalic( textCode.Font.Italic );
3001}
3002
3003
3005 const TEXTCODE_ID& aCadstarTextCodeID,
3006 const ALIGNMENT& aCadstarAlignment,
3007 const JUSTIFICATION& aCadstarJustification,
3008 const long long aCadstarOrientAngle,
3009 bool aMirrored )
3010{
3011 applyTextCodeIfExists( aKiCadTextItem, aCadstarTextCodeID );
3012 aKiCadTextItem->SetTextAngle( getAngle( aCadstarOrientAngle ) );
3013
3014 // Justification ignored for now as not supported in Eeschema, but leaving this code in
3015 // place for future upgrades.
3016 // TODO update this when Eeschema supports justification independent of anchor position.
3017 ALIGNMENT textAlignment = aCadstarAlignment;
3018
3019 // KiCad mirrors the justification and alignment when the symbol is mirrored but CADSTAR
3020 // specifies it post-mirroring. In contrast, if the text item itself is mirrored (not
3021 // supported in KiCad), CADSTAR specifies the alignment and justification pre-mirroring
3022 if( aMirrored )
3023 textAlignment = mirrorX( aCadstarAlignment );
3024
3025 auto setAlignment =
3026 [&]( EDA_TEXT* aText, ALIGNMENT aAlignment )
3027 {
3028 switch( aAlignment )
3029 {
3030 case ALIGNMENT::NO_ALIGNMENT: // Bottom left of the first line
3031 //No exact KiCad equivalent, so lets move the position of the text
3037 break;
3038
3042 break;
3043
3047 break;
3048
3052 break;
3053
3057 break;
3058
3062 break;
3063
3064 case ALIGNMENT::TOPLEFT:
3067 break;
3068
3072 break;
3073
3077 break;
3078 }
3079 };
3080
3081 SPIN_STYLE spin = getSpinStyle( aCadstarOrientAngle, aMirrored );
3082 EDA_ITEM* textEdaItem = dynamic_cast<EDA_ITEM*>( aKiCadTextItem );
3083 wxCHECK( textEdaItem, /* void */ ); // ensure this is a EDA_ITEM
3084
3085 if( textEdaItem->Type() == SCH_FIELD_T )
3086 {
3087 // Spin style not used. All text justifications are permitted. However, only orientations
3088 // of 0 deg or 90 deg are supported
3089 EDA_ANGLE angle = aKiCadTextItem->GetTextAngle();
3090 angle.Normalize();
3091
3092 int quadrant = KiROUND( angle.AsDegrees() / 90.0 );
3093 quadrant %= 4;
3094
3095 switch( quadrant )
3096 {
3097 case 0:
3098 angle = ANGLE_HORIZONTAL;
3099 break;
3100 case 1:
3101 angle = ANGLE_VERTICAL;
3102 break;
3103 case 2:
3104 angle = ANGLE_HORIZONTAL;
3105 textAlignment = rotate180( textAlignment );
3106 break;
3107 case 3:
3108 angle = ANGLE_VERTICAL;
3109 textAlignment = rotate180( textAlignment );
3110 break;
3111 default:
3112 wxFAIL_MSG( "Unknown Quadrant" );
3113 }
3114
3115 aKiCadTextItem->SetTextAngle( angle );
3116 setAlignment( aKiCadTextItem, textAlignment );
3117 }
3118 else if( textEdaItem->Type() == SCH_TEXT_T )
3119 {
3120 // Note spin style in a SCH_TEXT results in a vertical alignment GR_TEXT_V_ALIGN_BOTTOM
3121 // so need to adjust the location of the text element based on Cadstar's original text
3122 // alignment (anchor position).
3123 setAlignment( aKiCadTextItem, textAlignment );
3124 BOX2I bb = textEdaItem->GetBoundingBox();
3125 int off = static_cast<SCH_TEXT*>( aKiCadTextItem )->GetTextOffset();
3126 VECTOR2I pos;
3127
3128 // Change the anchor point of the text item to make it match the same bounding box
3129 // And correct the error introduced by the text offsetting in KiCad
3130 switch( spin )
3131 {
3132 case SPIN_STYLE::BOTTOM: pos = { bb.GetRight() - off, bb.GetTop() }; break;
3133 case SPIN_STYLE::UP: pos = { bb.GetRight() - off, bb.GetBottom() }; break;
3134 case SPIN_STYLE::LEFT: pos = { bb.GetRight() , bb.GetBottom() + off }; break;
3135 case SPIN_STYLE::RIGHT: pos = { bb.GetLeft() , bb.GetBottom() + off }; break;
3136 default: wxFAIL_MSG( "Unexpected Spin Style" ); break;
3137 }
3138
3139 aKiCadTextItem->SetTextPos( pos );
3140
3141 switch( spin )
3142 {
3143 case SPIN_STYLE::RIGHT: // Horiz Normal Orientation
3144 aKiCadTextItem->SetTextAngle( ANGLE_HORIZONTAL );
3145 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
3146 break;
3147
3148 case SPIN_STYLE::UP: // Vert Orientation UP
3149 aKiCadTextItem->SetTextAngle( ANGLE_VERTICAL );
3150 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
3151 break;
3152
3153 case SPIN_STYLE::LEFT: // Horiz Orientation - Right justified
3154 aKiCadTextItem->SetTextAngle( ANGLE_HORIZONTAL );
3155 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
3156 break;
3157
3158 case SPIN_STYLE::BOTTOM: // Vert Orientation BOTTOM
3159 aKiCadTextItem->SetTextAngle( ANGLE_VERTICAL );
3160 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
3161 break;
3162
3163 default:
3164 wxFAIL_MSG( "Unexpected Spin Style" );
3165 break;
3166 }
3167
3168 aKiCadTextItem->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
3169 }
3170 else if( SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( aKiCadTextItem ) )
3171 {
3172 // We don't want to change position of net labels as that would break connectivity
3173 label->SetSpinStyle( spin );
3174 }
3175 else
3176 {
3177 wxFAIL_MSG( "Unexpected item type" );
3178 }
3179}
3180
3181
3183{
3184 SCH_TEXT* kiTxt = new SCH_TEXT();
3185
3186 kiTxt->SetParent( m_schematic ); // set to the schematic for now to avoid asserts
3187 kiTxt->SetPosition( getKiCadPoint( aCadstarTextElement.Position ) );
3188 kiTxt->SetText( aCadstarTextElement.Text );
3189
3190 applyTextSettings( kiTxt, aCadstarTextElement.TextCodeID, aCadstarTextElement.Alignment,
3191 aCadstarTextElement.Justification, aCadstarTextElement.OrientAngle,
3192 aCadstarTextElement.Mirror );
3193
3194 return kiTxt;
3195}
3196
3197
3199 long long aScalingFactorNumerator,
3200 long long aScalingFactorDenominator )
3201{
3202 LIB_SYMBOL* retval = new LIB_SYMBOL( *aSymbol );
3203
3204 if( aScalingFactorNumerator == aScalingFactorDenominator )
3205 return retval; // 1:1 scale, nothing to do
3206
3207 auto scaleLen =
3208 [&]( int aLength ) -> int
3209 {
3210 return( aLength * aScalingFactorNumerator ) / aScalingFactorDenominator;
3211 };
3212
3213 auto scalePt =
3214 [&]( VECTOR2I aCoord ) -> VECTOR2I
3215 {
3216 return VECTOR2I( scaleLen( aCoord.x ), scaleLen( aCoord.y ) );
3217 };
3218
3219 auto scaleSize =
3220 [&]( VECTOR2I aSize ) -> VECTOR2I
3221 {
3222 return VECTOR2I( scaleLen( aSize.x ), scaleLen( aSize.y ) );
3223 };
3224
3225 LIB_ITEMS_CONTAINER& items = retval->GetDrawItems();
3226
3227 for( SCH_ITEM& item : items )
3228 {
3229 switch( item.Type() )
3230 {
3231 case KICAD_T::SCH_SHAPE_T:
3232 {
3233 SCH_SHAPE& shape = static_cast<SCH_SHAPE&>( item );
3234
3235 if( shape.GetShape() == SHAPE_T::ARC )
3236 {
3237 shape.SetPosition( scalePt( shape.GetPosition() ) );
3238 shape.SetStart( scalePt( shape.GetStart() ) );
3239 shape.SetEnd( scalePt( shape.GetEnd() ) );
3240 }
3241 else if( shape.GetShape() == SHAPE_T::POLY )
3242 {
3243 SHAPE_LINE_CHAIN& poly = shape.GetPolyShape().Outline( 0 );
3244
3245 for( size_t ii = 0; ii < poly.GetPointCount(); ++ii )
3246 poly.SetPoint( ii, scalePt( poly.CPoint( ii ) ) );
3247 }
3248 break;
3249 }
3250
3251 case KICAD_T::SCH_PIN_T:
3252 {
3253 SCH_PIN& pin = static_cast<SCH_PIN&>( item );
3254
3255 pin.SetPosition( scalePt( pin.GetPosition() ) );
3256 pin.SetLength( scaleLen( pin.GetLength() ) );
3257 break;
3258 }
3259
3260 case KICAD_T::SCH_TEXT_T:
3261 {
3262 SCH_TEXT& txt = static_cast<SCH_TEXT&>( item );
3263
3264 txt.SetPosition( scalePt( txt.GetPosition() ) );
3265 txt.SetTextSize( scaleSize( txt.GetTextSize() ) );
3266 break;
3267 }
3268
3269 default:
3270 break;
3271 }
3272 }
3273
3274 return retval;
3275}
3276
3277
3278void CADSTAR_SCH_ARCHIVE_LOADER::fixUpLibraryPins( LIB_SYMBOL* aSymbolToFix, int aGateNumber )
3279{
3280 auto compLambda =
3281 []( const VECTOR2I& aA, const VECTOR2I& aB )
3282 {
3283 return LexicographicalCompare( aA, aB ) < 0;
3284 };
3285
3286 // Store a list of vertical or horizontal segments in the symbol
3287 // Note: Need the custom comparison function to ensure the map is sorted correctly
3288 std::map<VECTOR2I, SHAPE_LINE_CHAIN, decltype( compLambda )> uniqueSegments( compLambda );
3289
3290 LIB_ITEMS_CONTAINER::ITERATOR shapeIt = aSymbolToFix->GetDrawItems().begin( SCH_SHAPE_T );
3291
3292 for( ; shapeIt != aSymbolToFix->GetDrawItems().end( SCH_SHAPE_T ); ++shapeIt )
3293 {
3294 SCH_SHAPE& shape = static_cast<SCH_SHAPE&>( *shapeIt );
3295
3296 if( aGateNumber > 0 && shape.GetUnit() != aGateNumber )
3297 continue;
3298
3299 if( shape.GetShape() != SHAPE_T::POLY )
3300 continue;
3301
3302 SHAPE_LINE_CHAIN poly = shape.GetPolyShape().Outline( 0 );
3303
3304 if( poly.GetPointCount() == 2 )
3305 {
3306 VECTOR2I pt0 = poly.CPoint( 0 );
3307 VECTOR2I pt1 = poly.CPoint( 1 );
3308
3309 if( pt0 != pt1 && uniqueSegments.count( pt0 ) == 0 && uniqueSegments.count( pt1 ) == 0 )
3310 {
3311 // we are only interested in vertical or horizontal segments
3312 if( pt0.x == pt1.x || pt0.y == pt1.y )
3313 {
3314 uniqueSegments.insert( { pt0, poly } );
3315 uniqueSegments.insert( { pt1, poly } );
3316 }
3317 }
3318 }
3319 }
3320
3321 for( SCH_PIN* pin : aSymbolToFix->GetPins( aGateNumber ) )
3322 {
3323 auto setPinOrientation =
3324 [&]( const EDA_ANGLE& aAngle )
3325 {
3326 EDA_ANGLE angle( aAngle );
3327 angle.Normalize180();
3328
3329 if( angle >= -ANGLE_45 && angle <= ANGLE_45 )
3330 pin->SetOrientation( PIN_ORIENTATION::PIN_RIGHT ); // 0 degrees
3331 else if( angle >= ANGLE_45 && angle <= ANGLE_135 )
3332 pin->SetOrientation( PIN_ORIENTATION::PIN_UP ); // 90 degrees
3333 else if( angle >= ANGLE_135 || angle <= -ANGLE_135 )
3334 pin->SetOrientation( PIN_ORIENTATION::PIN_LEFT ); // 180 degrees
3335 else
3336 pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN ); // -90 degrees
3337 };
3338
3339 if( uniqueSegments.count( pin->GetPosition() ) )
3340 {
3341 SHAPE_LINE_CHAIN& poly = uniqueSegments.at( pin->GetPosition() );
3342
3343 VECTOR2I otherPt = poly.CPoint( 0 );
3344
3345 if( otherPt == pin->GetPosition() )
3346 otherPt = poly.CPoint( 1 );
3347
3348 VECTOR2I vec( otherPt - pin->GetPosition() );
3349
3350 pin->SetLength( vec.EuclideanNorm() );
3351 setPinOrientation( EDA_ANGLE( vec ) );
3352 }
3353 }
3354}
3355
3356
3357std::pair<VECTOR2I, VECTOR2I>
3359{
3360 VECTOR2I upperLeft( Assignments.Settings.DesignLimit.x, 0 );
3361 VECTOR2I lowerRight( 0, Assignments.Settings.DesignLimit.y );
3362
3363 for( const VERTEX& v : aCadstarFigure.Shape.Vertices )
3364 {
3365 if( upperLeft.x > v.End.x )
3366 upperLeft.x = v.End.x;
3367
3368 if( upperLeft.y < v.End.y )
3369 upperLeft.y = v.End.y;
3370
3371 if( lowerRight.x < v.End.x )
3372 lowerRight.x = v.End.x;
3373
3374 if( lowerRight.y > v.End.y )
3375 lowerRight.y = v.End.y;
3376 }
3377
3378 for( CUTOUT cutout : aCadstarFigure.Shape.Cutouts )
3379 {
3380 for( const VERTEX& v : aCadstarFigure.Shape.Vertices )
3381 {
3382 if( upperLeft.x > v.End.x )
3383 upperLeft.x = v.End.x;
3384
3385 if( upperLeft.y < v.End.y )
3386 upperLeft.y = v.End.y;
3387
3388 if( lowerRight.x < v.End.x )
3389 lowerRight.x = v.End.x;
3390
3391 if( lowerRight.y > v.End.y )
3392 lowerRight.y = v.End.y;
3393 }
3394 }
3395
3396 VECTOR2I upperLeftKiCad = getKiCadPoint( upperLeft );
3397 VECTOR2I lowerRightKiCad = getKiCadPoint( lowerRight );
3398
3399 VECTOR2I size = lowerRightKiCad - upperLeftKiCad;
3400
3401 return { upperLeftKiCad, VECTOR2I( abs( size.x ), abs( size.y ) ) };
3402}
3403
3404
3406{
3407 VECTOR2I retval;
3408
3409 retval.x = getKiCadLength( aCadstarPoint.x - m_designCenter.x );
3410 retval.y = -getKiCadLength( aCadstarPoint.y - m_designCenter.y );
3411
3412 return retval;
3413}
3414
3415
3417 const VECTOR2I& aCadstarCentre )
3418{
3419 VECTOR2I retval;
3420
3421 retval.x = getKiCadLength( aCadstarPoint.x - aCadstarCentre.x );
3422 retval.y = -getKiCadLength( aCadstarPoint.y - aCadstarCentre.y );
3423
3424 return retval;
3425}
3426
3427
3429 const VECTOR2I& aMoveVector,
3430 const EDA_ANGLE& aRotation,
3431 const double& aScalingFactor,
3432 const VECTOR2I& aTransformCentre,
3433 const bool& aMirrorInvert )
3434{
3435 VECTOR2I retVal = aPoint;
3436
3437 if( aScalingFactor != 1.0 )
3438 {
3439 //scale point
3440 retVal -= aTransformCentre;
3441 retVal.x = KiROUND( retVal.x * aScalingFactor );
3442 retVal.y = KiROUND( retVal.y * aScalingFactor );
3443 retVal += aTransformCentre;
3444 }
3445
3446 if( aMirrorInvert )
3447 MIRROR( retVal.x, aTransformCentre.x );
3448
3449 if( !aRotation.IsZero() )
3450 RotatePoint( retVal, aTransformCentre, aRotation );
3451
3452 if( aMoveVector != VECTOR2I{ 0, 0 } )
3453 retVal += aMoveVector;
3454
3455 return retVal;
3456}
3457
3458
3460{
3461 return sqrt( ( (double) aPoint.x * (double) aPoint.x )
3462 + ( (double) aPoint.y * (double) aPoint.y ) );
3463}
const char * name
Definition: DXF_plotter.cpp:57
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:110
constexpr double SCH_IU_PER_MM
Definition: base_units.h:72
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
CADSTAR_PIN_TYPE
file: cadstar_archive_objects.h Contains common object definitions
#define SYMBOL_NAME_ATTRID
Symbol Name attribute ID - used for placement of designators on the schematic.
#define SIGNALNAME_ORIGIN_ATTRID
#define LINK_ORIGIN_ATTRID
#define PART_NAME_ATTRID
const wxString PartAcceptanceFieldName
const wxString PartNumberFieldName
const wxString PartNameFieldName
const wxString PartVersionFieldName
Loads a csa file into a KiCad SCHEMATIC object.
constexpr Vec Centre() const
Definition: box2.h:97
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:658
constexpr coord_type GetLeft() const
Definition: box2.h:228
constexpr coord_type GetRight() const
Definition: box2.h:217
constexpr const SizeVec & GetSize() const
Definition: box2.h:206
constexpr coord_type GetTop() const
Definition: box2.h:229
constexpr coord_type GetBottom() const
Definition: box2.h:222
static wxString EscapeFieldText(const wxString &aFieldText)
@ FRACTIONALGRID
Param1 = Units, Param2 = Divisor.
static const std::map< TEXT_FIELD_NAME, wxString > CADSTAR_TO_KICAD_FIELDS
Map between CADSTAR fields and KiCad text variables.
long TERMINAL_ID
Terminal is the pin identifier in the schematic.
TEXT_FIELD_NAME
These are special fields in text objects enclosed between the tokens '<@' and '>' such as <@[FIELD_NA...
ALIGNMENT
From CADSTAR Help: "Text Alignment enables you to define the position of an alignment origin for all ...
@ NO_ALIGNMENT
NO_ALIGNMENT has different meaning depending on the object type.
static const long UNDEFINED_VALUE
static wxString generateLibName(const wxString &aRefName, const wxString &aAlternateName)
wxString LAYER_ID
ID of a Sheet (if schematic) or board Layer (if PCB)
static void FixTextPositionNoAlignment(EDA_TEXT *aKiCadTextItem)
Corrects the position of a text element that had NO_ALIGNMENT in CADSTAR.
@ OUTLINE
Unfilled closed shape.
@ OPENSHAPE
Unfilled open shape. Cannot have cutouts.
@ SOLID
Filled closed shape (solid fill).
@ HATCHED
Filled closed shape (hatch fill).
static const double TXT_HEIGHT_RATIO
CADSTAR fonts are drawn on a 24x24 integer matrix, where the each axis goes from 0 to 24.
void checkPoint()
Updates m_progressReporter or throws if user cancelled.
static wxString HandleTextOverbar(wxString aCadstarString)
Convert a string with CADSTAR overbar characters to equivalent in KiCad.
JUSTIFICATION
From CADSTAR Help: "Multi Line Text can also be justified as Left, Centre or Right.
PROGRESS_REPORTER * m_progressReporter
bool CheckFileHeader(const std::filesystem::path &aPath) const
CADSTAR_PARTS_LIB_MODEL ReadFile(const std::filesystem::path &aPath) const
static SCH_FIELD * addNewFieldToSymbol(const wxString &aFieldName, std::unique_ptr< LIB_SYMBOL > &aKiCadSymbol)
void loadItemOntoKiCadSheet(const LAYER_ID &aCadstarSheetID, SCH_ITEM *aItem)
void Load(SCHEMATIC *aSchematic, SCH_SHEET *aRootSheet)
Loads a CADSTAR Schematic Archive file into the KiCad SCHEMATIC object given.
ROUTECODE getRouteCode(const ROUTECODE_ID &aCadstarRouteCodeID)
static wxString CreateLibName(const wxFileName &aFileName, const SCH_SHEET *aRootSheet)
std::map< BLOCK_PIN_ID, SCH_HIERLABEL * > m_sheetPinMap
Cadstar->KiCad Sheet Pins.
VECTOR2I applyTransform(const VECTOR2I &aPoint, const VECTOR2I &aMoveVector={ 0, 0 }, const EDA_ANGLE &aRotation=ANGLE_0, const double &aScalingFactor=1.0, const VECTOR2I &aTransformCentre={ 0, 0 }, const bool &aMirrorInvert=false)
std::map< SYMBOL_ID, SCH_GLOBALLABEL * > m_globalLabelsMap
Cadstar->KiCad Global Labels.
SCH_SYMBOL * loadSchematicSymbol(const SYMBOL &aCadstarSymbol, const LIB_SYMBOL &aKiCadPart, EDA_ANGLE &aComponentOrientation)
void applyTextSettings(EDA_TEXT *aKiCadTextItem, const TEXTCODE_ID &aCadstarTextCodeID, const ALIGNMENT &aCadstarAlignment, const JUSTIFICATION &aCadstarJustification, const long long aCadstarOrientAngle=0, bool aMirrored=false)
void loadSheetAndChildSheets(const LAYER_ID &aCadstarSheetID, const VECTOR2I &aPosition, const VECTOR2I &aSheetSize, const SCH_SHEET_PATH &aParentSheet)
wxString getAttributeName(const ATTRIBUTE_ID &aCadstarAttributeID)
std::vector< LIB_SYMBOL * > m_loadedSymbols
Loaded symbols so far.
PART getPart(const PART_ID &aCadstarPartID)
std::vector< LAYER_ID > findOrphanSheets()
std::map< BUS_ID, std::shared_ptr< BUS_ALIAS > > m_busesMap
Cadstar->KiCad Buses.
SCH_TEXT * getKiCadSchText(const TEXT &aCadstarTextElement)
std::map< TERMINAL_ID, wxString > TERMINAL_TO_PINNUM_MAP
Map between a terminal ID in a symbol definition to the pin number that should be imported into KiCad...
wxString getNetName(const NET_SCH &aNet)
std::pair< BLOCK_ID, TERMINAL_ID > BLOCK_PIN_ID
std::map< SYMBOL_ID, SCH_SYMBOL * > m_powerSymMap
Cadstar->KiCad Power Symbols.
std::pair< PART_ID, GATE_ID > PART_GATE_ID
VECTOR2I getKiCadLibraryPoint(const VECTOR2I &aCadstarPoint, const VECTOR2I &aCadstarCentre)
PART::DEFINITION::PIN getPartDefinitionPin(const PART &aCadstarPart, const GATE_ID &aGateID, const TERMINAL_ID &aTerminalID)
std::map< wxString, TERMINAL_ID > PINNUM_TO_TERMINAL_MAP
std::map< SYMDEF_ID, PINNUM_TO_TERMINAL_MAP > m_symDefTerminalsMap
int getTextHeightFromTextCode(const TEXTCODE_ID &aCadstarTextCodeID)
void loadChildSheets(const LAYER_ID &aCadstarSheetID, const SCH_SHEET_PATH &aSheet)
void applyToLibraryFieldAttribute(const ATTRIBUTE_LOCATION &aCadstarAttrLoc, const VECTOR2I &aSymbolOrigin, SCH_FIELD *aKiCadField)
double getPolarRadius(const VECTOR2I &aPoint)
void setFootprintOnSymbol(std::unique_ptr< LIB_SYMBOL > &aKiCadSymbol, const wxString &aFootprintName, const wxString &aFootprintAlternate)
void applyTextCodeIfExists(EDA_TEXT *aKiCadTextItem, const TEXTCODE_ID &aCadstarTextCodeID)
int getSheetNumber(const LAYER_ID &aCadstarSheetID)
void copySymbolItems(std::unique_ptr< LIB_SYMBOL > &aSourceSym, std::unique_ptr< LIB_SYMBOL > &aDestSym, int aDestUnit, bool aOverrideFields=true)
int getLineThickness(const LINECODE_ID &aCadstarLineCodeID)
TEXTCODE getTextCode(const TEXTCODE_ID &aCadstarTextCodeID)
SPIN_STYLE getSpinStyle(const long long &aCadstarOrientation, bool aMirror)
std::map< wxString, LIB_SYMBOL * > m_powerSymLibMap
NetName->KiCad Power Lib Symbol.
std::map< std::pair< wxString, wxString >, SYMDEF_ID > m_SymDefNamesCache
Cache storing symbol names and alternates to symdef IDs.
std::map< PART_ID, TERMINAL_TO_PINNUM_MAP > m_pinNumsMap
Cadstar Part->KiCad Pin number map.
std::vector< LIB_SYMBOL * > LoadPartsLib(const wxString &aFilename)
ELECTRICAL_PINTYPE getKiCadPinType(const CADSTAR_PIN_TYPE &aPinType)
wxString m_footprintLibName
Name of the footprint library to prepend all footprints with.
int getKiCadLength(long long aCadstarLength)
std::map< PART_ID, LIB_SYMBOL * > m_partMap
Cadstar->KiCad Parts.
bool isAttributeVisible(const ATTRIBUTE_ID &aCadstarAttributeID)
VECTOR2I getKiCadPoint(const VECTOR2I &aCadstarPoint)
EDA_ANGLE getAngle(const long long &aCadstarAngle)
std::map< wxString, SYMDEF_ID > m_DefaultSymDefNamesCache
Cache storing symbol names (default alternate) to symdef IDs.
void loadSymbolGateAndPartFields(const SYMDEF_ID &aSymdefID, const PART &aCadstarPart, const GATE_ID &aGateID, LIB_SYMBOL *aSymbol)
void loadFigure(const FIGURE &aCadstarFigure, const LAYER_ID &aCadstarSheetIDOverride, SCH_LAYER_ID aKiCadSchLayerID, const VECTOR2I &aMoveVector={ 0, 0 }, const EDA_ANGLE &aRotation=ANGLE_0, const double &aScalingFactor=1.0, const VECTOR2I &aTransformCentre={ 0, 0 }, const bool &aMirrorInvert=false)
std::map< PART_GATE_ID, SYMDEF_ID > m_partSymbolsMap
Map holding the symbols loaded so far for a particular PART_ID and GATE_ID.
LIB_SYMBOL * getScaledLibPart(const LIB_SYMBOL *aSymbol, long long aScalingFactorNumerator, long long aScalingFactorDenominator)
SYMDEF_ID getSymDefFromName(const wxString &aSymdefName, const wxString &aSymDefAlternate)
std::pair< VECTOR2I, VECTOR2I > getFigureExtentsKiCad(const FIGURE &aCadstarFigure)
std::map< LAYER_ID, SCH_SHEET * > m_sheetMap
Cadstar->KiCad Sheets.
POINT getLocationOfNetElement(const NET_SCH &aNet, const NETELEMENT_ID &aNetElementID)
void fixUpLibraryPins(LIB_SYMBOL *aSymbolToFix, int aGateNumber)
std::map< SYMDEF_ID, std::unique_ptr< const LIB_SYMBOL > > m_symDefMap
Cadstar->KiCad Lib Symbols loaded so far.
std::unique_ptr< LIB_SYMBOL > loadLibPart(const CADSTAR_PART_ENTRY &aPart)
ALIGNMENT rotate180(const ALIGNMENT &aCadstarAlignment)
long long getCadstarAngle(const EDA_ANGLE &aAngle)
void loadLibrarySymbolShapeVertices(const std::vector< VERTEX > &aCadstarVertices, const VECTOR2I &aSymbolOrigin, LIB_SYMBOL *aSymbol, int aGateNumber, int aLineThickness)
LINE_STYLE getLineStyle(const LINECODE_ID &aCadstarLineCodeID)
VECTOR2I m_designCenter
Required for calculating the offset to apply to the Cadstar design so that it fits in the KiCad canva...
ALIGNMENT mirrorX(const ALIGNMENT &aCadstarAlignment)
int getComponentOrientation(const EDA_ANGLE &aOrientAngle, EDA_ANGLE &aReturnedOrientation)
void loadShapeVertices(const std::vector< VERTEX > &aCadstarVertices, LINECODE_ID aCadstarLineCodeID, LAYER_ID aCadstarSheetID, SCH_LAYER_ID aKiCadSchLayerID, const VECTOR2I &aMoveVector={ 0, 0 }, const EDA_ANGLE &aRotation=ANGLE_0, const double &aScalingFactor=1.0, const VECTOR2I &aTransformCentre={ 0, 0 }, const bool &aMirrorInvert=false)
const LIB_SYMBOL * loadSymdef(const SYMDEF_ID &aSymdefID)
int getKiCadUnitNumberFromGate(const GATE_ID &aCadstarGateID)
void loadSymbolFieldAttribute(const ATTRIBUTE_LOCATION &aCadstarAttrLoc, const EDA_ANGLE &aComponentOrientation, bool aIsMirrored, SCH_FIELD *aKiCadField)
int KiCadUnitDivider
Use this value to convert units in this CSA file to KiCad units.
EDA_ANGLE Normalize()
Definition: eda_angle.h:221
double AsDegrees() const
Definition: eda_angle.h:113
bool IsZero() const
Definition: eda_angle.h:133
EDA_ANGLE Normalize180()
Definition: eda_angle.h:260
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:89
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:77
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:104
EDA_ITEM * GetParent() const
Definition: eda_item.h:103
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:279
SHAPE_T GetShape() const
Definition: eda_shape.h:125
void SetPolyShape(const SHAPE_POLY_SET &aShape)
Definition: eda_shape.h:287
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:167
void SetStart(const VECTOR2I &aStart)
Definition: eda_shape.h:134
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:130
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:171
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Set the three controlling points for an arc.
Definition: eda_shape.cpp:607
void SetFillMode(FILL_T aFill)
Definition: eda_shape.h:106
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:79
int GetTextHeight() const
Definition: eda_text.h:247
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:130
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition: eda_text.cpp:419
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:94
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:464
int GetTextWidth() const
Definition: eda_text.h:244
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition: eda_text.cpp:321
void SetTextWidth(int aWidth)
Definition: eda_text.cpp:442
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:290
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.cpp:196
void SetTextHeight(int aHeight)
Definition: eda_text.cpp:453
void SetBold(bool aBold)
Set the text to be bold - this will also update the font if needed.
Definition: eda_text.cpp:240
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:182
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition: eda_text.cpp:204
int GetTextThickness() const
Definition: eda_text.h:122
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition: eda_text.cpp:212
void SetMultilineAllowed(bool aAllow)
Definition: eda_text.cpp:305
VECTOR2I GetTextSize() const
Definition: eda_text.h:241
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition: eda_text.cpp:313
iterator end()
Returns a read/write iterator that points to one past the last element in the EE_RTREE.
Definition: sch_rtree.h:285
iterator begin()
Returns a read/write iterator that points to the first element in the EE_RTREE N.B.
Definition: sch_rtree.h:276
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
int SetLibItemName(const UTF8 &aLibItemName)
Override the library item name portion of the LIB_ID to aLibItemName.
Definition: lib_id.cpp:110
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition: lib_id.cpp:99
UTF8 Format() const
Definition: lib_id.cpp:118
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
Definition: lib_id.cpp:191
Define a library symbol object.
Definition: lib_symbol.h:78
void SetUnitCount(int aCount, bool aDuplicateDrawItems=true)
Set the units per symbol count.
std::vector< SCH_PIN * > GetPins(int aUnit=0, int aBodyStyle=0) const
Return a list of pin object pointers from the draw item list.
Definition: lib_symbol.cpp:810
SCH_FIELD & GetValueField() const
Return reference to the value field.
std::vector< SCH_PIN * > GetAllLibPins() const
Return a list of pin pointers for all units / converts.
Definition: lib_symbol.cpp:842
void SetPower()
Definition: lib_symbol.cpp:405
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition: lib_symbol.h:499
wxString GetName() const override
Definition: lib_symbol.h:137
SCH_FIELD & GetReferenceField() const
Return reference to the reference designator field.
void AddDrawItem(SCH_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
Definition: lib_symbol.cpp:796
virtual void SetName(const wxString &aName)
Definition: lib_symbol.cpp:288
void sort()
Definition: multivector.h:248
ITERATOR_BASE< SCH_ITEM, MULTIVECTOR< SCH_ITEM, FIRST_TYPE_VAL, LAST_TYPE_VAL >, typename ITEM_PTR_VECTOR::iterator > ITERATOR
The const iterator.
Definition: multivector.h:165
ITERATOR end(int aType=UNDEFINED_TYPE)
Definition: multivector.h:195
ITERATOR begin(int aType=UNDEFINED_TYPE)
Definition: multivector.h:189
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition: page_info.h:59
void SetHeightMils(double aHeightInMils)
Definition: page_info.cpp:261
const VECTOR2D GetSizeIU(double aIUScale) const
Gets the page size in internal units.
Definition: page_info.h:171
void SetWidthMils(double aWidthInMils)
Definition: page_info.cpp:247
virtual void SetNumPhases(int aNumPhases)=0
Set the number of phases.
virtual void BeginPhase(int aPhase)=0
Initialize the aPhase virtual zone of the dialog progress bar.
virtual void SetMaxProgress(int aMaxProgress)=0
Fix the value that gives the 100 percent progress bar length (inside the current virtual zone).
Container for project specific data.
Definition: project.h:64
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:135
virtual std::map< wxString, wxString > & GetTextVars() const
Definition: project.cpp:84
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
Holds all the data relating to one schematic.
Definition: schematic.h:77
PROJECT & Prj() const override
Return a reference to the project this schematic is part of.
Definition: schematic.h:92
void SetSize(const VECTOR2I &aSize)
Definition: sch_bus_entry.h:74
Class for a wire to bus entry.
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:51
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
Definition: sch_field.cpp:1227
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_field.cpp:1465
void SetName(const wxString &aName)
Definition: sch_field.cpp:1202
void SetText(const wxString &aText) override
Definition: sch_field.cpp:1212
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
Definition: sch_label.cpp:1857
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
Definition: sch_label.cpp:2038
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:166
int GetUnit() const
Definition: sch_item.h:229
void SetLayer(SCH_LAYER_ID aLayer)
Definition: sch_item.h:282
virtual void SetUnit(int aUnit)
Definition: sch_item.h:228
SCH_ITEM * Duplicate(bool doClone=false) const
Routine to create a new copy of given item.
Definition: sch_item.cpp:131
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_junction.h:108
void SetShape(LABEL_FLAG_SHAPE aShape)
Definition: sch_label.h:178
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_label.cpp:371
void AutoplaceFields(SCH_SCREEN *aScreen, bool aManual) override
Definition: sch_label.cpp:563
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
Definition: sch_label.cpp:297
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:41
void SetStartPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:137
void SetLineWidth(const int aSize)
Definition: sch_line.cpp:321
VECTOR2I GetEndPoint() const
Definition: sch_line.h:141
VECTOR2I GetStartPoint() const
Definition: sch_line.h:136
void SetLineStyle(const LINE_STYLE aStyle)
Definition: sch_line.cpp:292
void SetEndPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:142
void SetNumber(const wxString &aNumber)
Definition: sch_pin.cpp:514
const PAGE_INFO & GetPageSettings() const
Definition: sch_screen.h:130
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Definition: sch_screen.cpp:153
void AddBusAlias(std::shared_ptr< BUS_ALIAS > aAlias)
Add a bus alias definition (and transfers ownership of the pointer).
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: sch_screen.h:131
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:108
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
Definition: sch_screen.cpp:118
void Update(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Update aItem's bounding box in the tree.
Definition: sch_screen.cpp:316
void SetPosition(const VECTOR2I &aPos) override
Definition: sch_shape.h:71
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: sch_shape.cpp:63
void AddPoint(const VECTOR2I &aPosition)
Definition: sch_shape.cpp:576
VECTOR2I GetPosition() const override
Definition: sch_shape.h:70
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
void SetPageNumber(const wxString &aPageNumber)
Set the sheet instance user definable page number.
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:66
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:57
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition: sch_sheet.h:306
void AddPin(SCH_SHEET_PIN *aSheetPin)
Add aSheetPin to the sheet.
Definition: sch_sheet.cpp:429
std::vector< SCH_FIELD > & GetFields()
Definition: sch_sheet.h:93
bool LocatePathOfScreen(SCH_SCREEN *aScreen, SCH_SHEET_PATH *aList)
Search the existing hierarchy for an instance of screen loaded from aFileName.
Definition: sch_sheet.cpp:821
VECTOR2I GetSize() const
Definition: sch_sheet.h:112
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:110
VECTOR2I GetPosition() const override
Definition: sch_sheet.h:400
void SetFields(const std::vector< SCH_FIELD > &aFields)
Set multiple schematic fields.
Definition: sch_sheet.cpp:409
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Definition: sch_sheet.cpp:173
void AutoplaceFields(SCH_SCREEN *aScreen, bool aManual) override
Definition: sch_sheet.cpp:666
static bool ClassOf(const EDA_ITEM *aItem)
Definition: sch_sheet.h:72
Schematic symbol object.
Definition: sch_symbol.h:104
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_symbol.h:808
int GetFieldCount() const
Return the number of fields in this symbol.
Definition: sch_symbol.h:606
SCH_FIELD * FindField(const wxString &aFieldName, bool aIncludeDefaultFields=true, bool aCaseInsensitive=false)
Search for a SCH_FIELD with aFieldName.
SCH_FIELD * GetField(MANDATORY_FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition: sch_symbol.cpp:939
void UpdatePins()
Updates the cache of SCH_PIN objects for each pin.
Definition: sch_symbol.cpp:315
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
Definition: sch_symbol.cpp:779
void SetOrientation(int aOrientation)
Compute the new transform matrix based on aOrientation for the symbol which is applied to the current...
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
BOX2I GetBodyAndPinsBoundingBox() const
Return a bounding box for the symbol body and pins but not the fields.
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly)
Populate a std::vector with SCH_FIELDs.
Definition: sch_symbol.cpp:987
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition: sch_symbol.h:212
VECTOR2I GetPosition() const override
Definition: sch_text.h:141
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_text.h:142
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: sch_text.cpp:385
const VECTOR2I & GetArcMid() const
Definition: shape_arc.h:116
const VECTOR2I & GetP1() const
Definition: shape_arc.h:115
const VECTOR2I & GetP0() const
Definition: shape_arc.h:114
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_LINE_CHAIN Reverse() const
Reverse point order in the line chain.
void SetPoint(int aIndex, const VECTOR2I &aPos)
Move a point to a specific location.
int FindSegment(const VECTOR2I &aP, int aThreshold=1) const
Search for segment containing point aP.
int Intersect(const SEG &aSeg, INTERSECTIONS &aIp) const
Find all intersection points between our line chain and the segment aSeg.
void Replace(int aStartIndex, int aEndIndex, const VECTOR2I &aP)
Replace points with indices in range [start_index, end_index] with a single point aP.
virtual size_t GetPointCount() const override
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
const VECTOR2I NearestPoint(const VECTOR2I &aP, bool aAllowInternalShapePoints=true) const
Find a point on the line chain that is closest to point aP.
std::vector< INTERSECTION > INTERSECTIONS
const std::vector< VECTOR2I > & CPoints() const
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
SPIN_STYLE MirrorX()
Mirror the label spin style across the X axis or simply swaps up and bottom.
Definition: sch_label.cpp:123
SPIN_STYLE MirrorY()
Mirror the label spin style across the Y axis or simply swaps left and right.
Definition: sch_label.cpp:139
SPIN_STYLE RotateCCW()
Definition: sch_label.cpp:107
Simple container to manage line stroke parameters.
Definition: stroke_params.h:79
virtual void SetShowPinNumbers(bool aShow)
Set or clear the pin number visibility flag.
Definition: symbol.h:129
virtual void SetShowPinNames(bool aShow)
Set or clear the pin name visibility flag.
Definition: symbol.h:123
wxString wx_str() const
Definition: utf8.cpp:45
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:283
#define DEFAULT_WIRE_WIDTH_MILS
The default bus width in mils. (can be changed in preference menu)
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:401
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:403
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition: eda_angle.h:398
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition: eda_angle.h:397
static constexpr EDA_ANGLE ANGLE_45
Definition: eda_angle.h:402
static constexpr EDA_ANGLE ANGLE_270
Definition: eda_angle.h:406
static constexpr EDA_ANGLE ANGLE_180
Definition: eda_angle.h:405
static constexpr EDA_ANGLE ANGLE_135
Definition: eda_angle.h:404
static const std::string KiCadSchematicFileExtension
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:39
SCH_LAYER_ID
Eeschema drawing layers.
Definition: layer_ids.h:353
@ LAYER_DEVICE
Definition: layer_ids.h:370
@ LAYER_WIRE
Definition: layer_ids.h:356
@ LAYER_NOTES
Definition: layer_ids.h:371
@ LAYER_BUS
Definition: layer_ids.h:357
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
constexpr void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition: mirror.h:45
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:100
ELECTRICAL_PINTYPE
The symbol library pin object electrical types used in ERC tests.
Definition: pin_type.h:36
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ SHEETNAME
Definition: sch_sheet.h:45
@ SHEETFILENAME
Definition: sch_sheet.h:46
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
std::vector< SCH_FIELD > SCH_FIELDS
A container for several SCH_FIELD items.
Definition: sch_symbol.h:65
#define SIM_DEVICE_FIELD
Definition: sim_model.h:52
#define SIM_PARAMS_FIELD
Definition: sim_model.h:55
void wxStringSplit(const wxString &aText, wxArrayString &aStrings, wxChar aSplitter)
Split aString to a string list separated at aSplitter.
bool ReplaceIllegalFileNameChars(std::string *aName, int aReplaceChar)
Checks aName for illegal file name characters.
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_LIBID
Definition: string_utils.h:54
LINE_STYLE
Dashed line types.
Definition: stroke_params.h:46
std::map< ATTRIBUTE_ID, ATTRCOL > AttributeColors
JUSTIFICATION Justification
Note: Justification has no effect on single lines of text.
ALIGNMENT Alignment
In CADSTAR The default alignment for a TEXT object (when "(No Alignment()" is selected) Bottom Left o...
bool HasLocation
Flag to know if this ATTRIBUTE_VALUE has a location i.e.
std::map< LINECODE_ID, LINECODE > LineCodes
std::map< ATTRIBUTE_ID, ATTRNAME > AttributeNames
std::map< ROUTECODE_ID, ROUTECODE > RouteCodes
std::map< TEXTCODE_ID, TEXTCODE > TextCodes
Represents a cutout in a closed shape (e.g.
long ScaleRatioNumerator
Documentation symbols can be arbitrarily scaled when added to a design.
long ScaleRatioDenominator
Documentation symbols can be arbitrarily scaled when added to a design.
POINT Origin
Origin of the component (this is used as the reference point when placing the component in the design...
LAYER_ID LayerID
Move all objects in the Symdef to this layer.
SYMDEF_ID SymdefID
Normally documentation symbols only have TEXT, FIGURE and TEXT_LOCATION objects which are all drawn o...
long Modifier1
It seems this is related to weight. 400=Normal, 700=Bold.
GRID ScreenGrid
From CADSTAR Help: "There is one Screen Grid, which is visible as dots on the screen.
long Param1
Either Units or X step, depending on Type (see GRID_TYPE for more details)
long Param2
Either Divisor or Y step, depending on Type (see GRID_TYPE for more details)
wxString Name
This is undefined (wxEmptyString) if the net is unnamed.
long SignalNum
This is undefined if the net has been given a name.
std::map< TEXT_FIELD_NAME, wxString > TextFieldToValuesMap
Values for the text field elements used in the CADSTAR design extracted from the text element instanc...
std::map< wxString, wxString > FilenamesToTextMap
CADSTAR doesn't have user defined text fields but does allow loading text from a file.
std::set< TEXT_FIELD_NAME > InconsistentTextFields
Text fields need to be updated in CADSTAR and it is possible that they are not consistent across text...
std::map< PART_ID, PART > PartDefinitions
bool HidePinNames
Specifies whether to display the pin names/identifier in the schematic symbol or not.
std::map< ATTRIBUTE_ID, ATTRIBUTE_VALUE > AttributeValues
Some attributes are defined within the part definition, whilst others are defined in the part.
std::map< PART_DEFINITION_PIN_ID, PIN > Pins
std::map< ATTRIBUTE_ID, ATTRIBUTE_VALUE > AttributeValues
Some attributes are defined within the part definition, whilst others are defined in the part itself.
Represents a point in x,y coordinates.
SHAPE_POLY_SET ConvertToPolySet(const std::function< VECTOR2I(const VECTOR2I &)> aCadstarToKicadPointCallback, double aAccuracy) const
std::vector< CUTOUT > Cutouts
Not Applicable to OPENSHAPE Type.
std::map< FIGURE_ID, FIGURE > Figures
std::map< ATTRIBUTE_ID, TEXT_LOCATION > TextLocations
This contains location of any attributes, including designator position.
POINT Origin
Origin of the component (this is used as the reference point when placing the component in the design...
wxString Alternate
This is in addition to ReferenceName.
std::map< ATTRIBUTE_ID, ATTRIBUTE_VALUE > AttributeValues
These attributes might also have a location.
long Width
Defaults to 0 if using system fonts or, if using CADSTAR font, default to equal height (1:1 aspect ra...
Corresponds to CADSTAR "origin".
ALIGNMENT Alignment
In CADSTAR The default alignment for a TEXT object (when "(No Alignment()" is selected) Bottom Left o...
JUSTIFICATION Justification
Note: Justification has no effect on single lines of text.
< Nodename = "VARIANT" or "VMASTER" (master variant
Represents a vertex in a shape.
SHAPE_ARC BuildArc(const VECTOR2I &aPrevPoint, const std::function< VECTOR2I(const VECTOR2I &)> aCadstarToKicadPointCallback) const
CADSTAR Parts Library (*.lib) model - a data structure describing the contents of the file format.
std::vector< CADSTAR_PART_ENTRY > m_PartEntries
std::string m_ComponentStem
std::map< std::string, std::vector< CADSTAR_PART_PIN > > m_HiddenPins
Pins with an implied electrical connection to a net, not part of any symbol (Note: we probably will n...
std::map< std::string, CADSTAR_ATTRIBUTE_VALUE > m_SchAttributes
Dollar sign ($) line $[!]<SCM Attribute name>(<Attribute value>) Attributes related to the schematic ...
std::map< std::string, CADSTAR_ATTRIBUTE_VALUE > m_SchAndPcbAttributes
At symbol (@) line [@[!]<SCM/PCB Attribute name>(<Attribute value>)] Attributes related to the PCB co...
std::vector< CADSTAR_PART_SYMBOL_ENTRY > m_Symbols
Symbols that form this part.
std::map< std::string, std::string > m_UserAttributes
Star (*) line *<User-defined name> This line is ignored by CADSTAR.
std::map< long, std::string > m_PinNamesMap
Map of pin identifiers to alphanumeric pin names Pin names can be a maximum of 10 characters (Typical...
std::optional< std::string > m_AcceptancePartName
bool m_PinsVisible
std::optional< std::string > m_Pcb_alternate
std::optional< std::string > m_Version
std::string m_Name
std::optional< std::string > m_Description
std::optional< std::string > m_Number
std::string m_Pcb_component
std::optional< std::string > m_SpiceModel
std::map< std::string, CADSTAR_ATTRIBUTE_VALUE > m_PcbAttributes
Percentage sign (%) line %[!]<PCB Attribute name>(<Attribute value>) Attributes related to the PCB co...
std::optional< std::string > m_Value
std::map< std::string, CADSTAR_ATTRIBUTE_VALUE > m_PartAttributes
Tilde (~) line ~[!]<Parts Library Attribute Name>(<Attribute Value>) Attributes related to the Part i...
std::map< long, std::string > m_PinLabelsMap
Map of pin identifiers to alphanumeric pin labels.
std::string m_SymbolName
std::vector< CADSTAR_PART_PIN > m_Pins
std::optional< std::string > m_SymbolAlternateName
TYPE Type
Determines what the associated layer is, whether parent, child or clone.
LAYER_ID LayerID
The sheet block is on (TODO: verify this is true)
LAYER_ID AssocLayerID
Parent or Child linked sheet.
std::map< TERMINAL_ID, TERMINAL > Terminals
LAYER_ID LayerID
Sheet on which bus is located.
std::map< REUSEBLOCK_ID, REUSEBLOCK > ReuseBlocks
std::map< DOCUMENTATION_SYMBOL_ID, DOCUMENTATION_SYMBOL > DocumentationSymbols
std::map< SYMDEF_ID, SYMDEF_SCM > SymbolDefinitions
std::map< NETELEMENT_ID, DANGLER > Danglers
std::map< NETELEMENT_ID, SYM_TERM > Terminals
std::map< NETELEMENT_ID, BUS_TERM > BusTerminals
std::map< NETELEMENT_ID, BLOCK_TERM > BlockTerminals
std::map< NETELEMENT_ID, JUNCTION_SCH > Junctions
std::vector< LAYER_ID > SheetOrder
A vector to also store the order in which sheets are to be displayed.
std::map< LAYER_ID, SHEET_NAME > SheetNames
LAYER_ID LayerID
Sheet on which symbol is located.
std::map< ATTRIBUTE_ID, ATTRIBUTE_VALUE > AttributeValues
GATE_ID GateID
The gate this symbol represents within the associated Part.
long ScaleRatioNumerator
Symbols can be arbitrarily scaled in CADSTAR.
std::map< TERMINAL_ID, SYMPINNAME_LABEL > PinNames
Identifier of the pin in the PCB Equivalent to KiCad's Pin Number.
std::map< TERMINAL_ID, PIN_NUM > PinNumbers
This seems to only appear in older designs and is similar to PinNames but only allowing numerical val...
std::map< TERMINAL_ID, PIN_NUM_LABEL_LOC > PinLabelLocations
std::map< TERMINAL_ID, PIN_NUM_LABEL_LOC > PinNumberLocations
std::map< TERMINAL_ID, TERMINAL > Terminals
POINT Position
Pad position within the component's coordinate frame.
constexpr int IUToMils(int iu) const
Definition: base_units.h:99
const double IU_PER_MILS
Definition: base_units.h:77
constexpr int MilsToIU(int mils) const
Definition: base_units.h:93
@ VALUE_FIELD
Field Value of part, i.e. "3.3K".
@ REFERENCE_FIELD
Field Reference of part, i.e. "IC21".
constexpr int delta
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:229
@ SCH_SYMBOL_T
Definition: typeinfo.h:172
@ SCH_FIELD_T
Definition: typeinfo.h:150
@ SCH_SHAPE_T
Definition: typeinfo.h:149
@ SCH_SHEET_PIN_T
Definition: typeinfo.h:173
@ SCH_TEXT_T
Definition: typeinfo.h:151
constexpr int sign(T val)
Definition: util.h:159
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:691
constexpr int LexicographicalCompare(const VECTOR2< T > &aA, const VECTOR2< T > &aB)
Definition: vector2d.h:640
Definition of file extensions used in Kicad.