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 The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License 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 3percent 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" //format:allow
542 "Maximum permitted design size: %.2f, %.2f millimeters.\n" ), //format:allow
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->Project().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( FIELD_T::REFERENCE );
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->GetField( PartNameFieldName );
789
790 if( !partField )
791 partField = symbol->AddField( SCH_FIELD( symbol, FIELD_T::USER, PartNameFieldName ) );
792
793 wxASSERT( partField->GetName() == PartNameFieldName );
794
795 wxString partname = getPart( sym.PartRef.RefID ).Name;
796 partname.Replace( wxT( "\n" ), wxT( "\\n" ) );
797 partname.Replace( wxT( "\r" ), wxT( "\\r" ) );
798 partname.Replace( wxT( "\t" ), wxT( "\\t" ) );
799 partField->SetText( partname );
800
801 loadSymbolFieldAttribute( sym.PartRef.AttrLoc, symOrient, sym.Mirror, partField );
802
804 }
805
806 for( auto& attr : sym.AttributeValues )
807 {
808 ATTRIBUTE_VALUE attrVal = attr.second;
809
810 if( attrVal.HasLocation )
811 {
812 wxString attrName = getAttributeName( attrVal.AttributeID );
813 SCH_FIELD* attrField = symbol->GetField( attrName );
814
815 if( !attrField )
816 attrField = symbol->AddField( SCH_FIELD( symbol, FIELD_T::USER, attrName ) );
817
818 wxASSERT( attrField->GetName() == attrName );
819
820 attrVal.Value.Replace( wxT( "\n" ), wxT( "\\n" ) );
821 attrVal.Value.Replace( wxT( "\r" ), wxT( "\\r" ) );
822 attrVal.Value.Replace( wxT( "\t" ), wxT( "\\t" ) );
823 attrField->SetText( attrVal.Value );
824
825 loadSymbolFieldAttribute( attrVal.AttributeLocation, symOrient, sym.Mirror,
826 attrField );
827 attrField->SetVisible( isAttributeVisible( attrVal.AttributeID ) );
828 }
829 }
830 }
831 else if( sym.IsSymbolVariant )
832 {
834 {
835 THROW_IO_ERROR( wxString::Format( _( "Symbol ID '%s' references library symbol "
836 "'%s' which could not be found in the "
837 "library. Did you export all items of the "
838 "design?" ),
839 sym.ID,
840 sym.PartRef.RefID ) );
841 }
842
843 SYMDEF_SCM libSymDef = Library.SymbolDefinitions.at( sym.SymdefID );
844
845 if( libSymDef.Terminals.size() != 1 )
846 {
847 THROW_IO_ERROR( wxString::Format( _( "Symbol ID '%s' is a signal reference or "
848 "global signal but it has too many pins. The "
849 "expected number of pins is 1 but %d were "
850 "found." ),
851 sym.ID,
852 libSymDef.Terminals.size() ) );
853 }
854
855 if( sym.SymbolVariant.Type == SYMBOLVARIANT::TYPE::GLOBALSIGNAL )
856 {
857 SYMDEF_ID symID = sym.SymdefID;
858 LIB_SYMBOL* kiPart = nullptr;
859
860 // In CADSTAR "GlobalSignal" is a special type of symbol which defines
861 // a Power Symbol. The "Alternate" name defines the default net name of
862 // the power symbol but this can be overridden in the design itself.
863 wxString libraryNetName = Library.SymbolDefinitions.at( symID ).Alternate;
864
865 // Name of the net that the symbol instance in CADSTAR refers to:
866 wxString symbolInstanceNetName = sym.SymbolVariant.Reference;
867 symbolInstanceNetName = EscapeString( symbolInstanceNetName, CTX_LIBID );
868
869 // Name of the symbol we will use for saving the part in KiCad
870 // Note: In CADSTAR all power symbols will start have the reference name be
871 // "GLOBALSIGNAL" followed by the default net name, so it makes sense to save
872 // the symbol in KiCad as the default net name as well.
873 wxString libPartName = libraryNetName;
874
875 // In CADSTAR power symbol instances can refer to a different net to that defined
876 // in the library. This causes problems in KiCad v6 as it breaks connectivity when
877 // the user decides to update all symbols from library. We handle this by creating
878 // individual versions of the power symbol for each net name.
879 if( libPartName != symbolInstanceNetName )
880 {
881 libPartName += wxT( " (" ) + symbolInstanceNetName + wxT( ")" );
882 }
883
884 if( m_powerSymLibMap.find( libPartName ) == m_powerSymLibMap.end() )
885 {
886 const LIB_SYMBOL* templatePart = loadSymdef( symID );
887 wxCHECK( templatePart, /*void*/ );
888
889 kiPart = new LIB_SYMBOL( *templatePart );
890 kiPart->SetGlobalPower();
891 kiPart->SetName( libPartName );
892 kiPart->GetValueField().SetText( symbolInstanceNetName );
893 kiPart->SetShowPinNames( false );
894 kiPart->SetShowPinNumbers( false );
895
896 std::vector<SCH_PIN*> pins = kiPart->GetPins();
897 wxCHECK( pins.size() == 1, /*void*/ );
898
899 pins.at( 0 )->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
900 pins.at( 0 )->SetName( symbolInstanceNetName );
901
902 if( libSymDef.TextLocations.find( SIGNALNAME_ORIGIN_ATTRID )
903 != libSymDef.TextLocations.end() )
904 {
905 TEXT_LOCATION& txtLoc =
907
908 VECTOR2I valPos = getKiCadLibraryPoint( txtLoc.Position, libSymDef.Origin );
909
910 kiPart->GetValueField().SetPosition( valPos );
911 kiPart->GetValueField().SetVisible( true );
912 }
913 else
914 {
915 kiPart->GetValueField().SetVisible( false );
916 }
917
918 kiPart->GetReferenceField().SetText( "#PWR" );
919 kiPart->GetReferenceField().SetVisible( false );
920 m_loadedSymbols.push_back( kiPart );
921 m_powerSymLibMap.insert( { libPartName, kiPart } );
922 }
923 else
924 {
925 kiPart = m_powerSymLibMap.at( libPartName );
926 wxASSERT( kiPart->GetValueField().GetText() == symbolInstanceNetName );
927 }
928
929 LIB_SYMBOL* scaledPart = getScaledLibPart( kiPart, sym.ScaleRatioNumerator,
931
932 EDA_ANGLE returnedOrient = ANGLE_0;
933 SCH_SYMBOL* symbol = loadSchematicSymbol( sym, *scaledPart, returnedOrient );
934 m_powerSymMap.insert( { sym.ID, symbol } );
935
936 delete scaledPart;
937 }
938 else if( sym.SymbolVariant.Type == SYMBOLVARIANT::TYPE::SIGNALREF )
939 {
940 // There should only be one pin and we'll use that to set the position
941 TERMINAL& symbolTerminal = libSymDef.Terminals.begin()->second;
942 VECTOR2I terminalPosOffset = symbolTerminal.Position - libSymDef.Origin;
943 EDA_ANGLE rotate = getAngle( sym.OrientAngle );
944
945 if( sym.Mirror )
946 rotate += ANGLE_180;
947
948 RotatePoint( terminalPosOffset, -rotate );
949
950 SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL;
951 netLabel->SetPosition( getKiCadPoint( (VECTOR2I)sym.Origin + terminalPosOffset ) );
952 netLabel->SetText( "***UNKNOWN NET****" ); // This should be later updated when we load the netlist
953 netLabel->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 50 ), schIUScale.MilsToIU( 50 ) ) );
954
955 SYMDEF_SCM symbolDef = Library.SymbolDefinitions.at( sym.SymdefID );
956
957 if( symbolDef.TextLocations.count( LINK_ORIGIN_ATTRID ) )
958 {
959 TEXT_LOCATION linkOrigin = symbolDef.TextLocations.at( LINK_ORIGIN_ATTRID );
960 applyTextSettings( netLabel, linkOrigin.TextCodeID, linkOrigin.Alignment,
961 linkOrigin.Justification );
962 }
963
964 netLabel->SetSpinStyle( getSpinStyle( sym.OrientAngle, sym.Mirror ) );
965
966 if( libSymDef.Alternate.Lower().Contains( "in" ) )
967 netLabel->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
968 else if( libSymDef.Alternate.Lower().Contains( "bi" ) )
969 netLabel->SetShape( LABEL_FLAG_SHAPE::L_BIDI );
970 else if( libSymDef.Alternate.Lower().Contains( "out" ) )
971 netLabel->SetShape( LABEL_FLAG_SHAPE::L_OUTPUT );
972 else
973 netLabel->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED );
974
975 SCH_SCREEN* screen = m_sheetMap.at( sym.LayerID )->GetScreen();
976
977 // autoplace intersheet refs
978 netLabel->AutoplaceFields( screen, AUTOPLACE_AUTO );
979
980 screen->Append( netLabel );
981 m_globalLabelsMap.insert( { sym.ID, netLabel } );
982 }
983 else
984 {
985 wxASSERT_MSG( false, "Unknown Symbol Variant." );
986 }
987 }
988 else
989 {
990 m_reporter->Report( wxString::Format( _( "Symbol ID '%s' is of an unknown type. It is "
991 "neither a symbol or a net power / symbol. "
992 "The symbol was not loaded." ),
993 sym.ID ),
995 }
996
997 if( sym.ScaleRatioDenominator != 1 || sym.ScaleRatioNumerator != 1 )
998 {
999 wxString symbolName = sym.ComponentRef.Designator;
1000
1001 if( symbolName.empty() )
1002 symbolName = wxString::Format( "ID: %s", sym.ID );
1003 else
1004 symbolName += sym.GateID;
1005
1006 m_reporter->Report( wxString::Format( _( "Symbol '%s' is scaled in the original "
1007 "CADSTAR schematic but this is not supported "
1008 "in KiCad. When the symbol is reloaded from "
1009 "the library, it will revert to the original "
1010 "1:1 scale." ),
1011 symbolName,
1012 sym.PartRef.RefID ),
1014 }
1015 }
1016}
1017
1018
1020{
1021 for( std::pair<BUS_ID, BUS> busPair : Schematic.Buses )
1022 {
1023 BUS bus = busPair.second;
1024 bool firstPt = true;
1025 VERTEX last;
1026
1027 if( bus.LayerID != wxT( "NO_SHEET" ) )
1028 {
1029 SCH_SCREEN* screen = m_sheetMap.at( bus.LayerID )->GetScreen();
1030 std::shared_ptr<BUS_ALIAS> kiBusAlias = std::make_shared<BUS_ALIAS>();
1031
1032 kiBusAlias->SetName( bus.Name );
1033 kiBusAlias->SetParent( screen );
1034 screen->AddBusAlias( kiBusAlias );
1035 m_busesMap.insert( { bus.ID, kiBusAlias } );
1036
1037 SCH_LABEL* label = new SCH_LABEL();
1038
1039 wxString busname = HandleTextOverbar( bus.Name );
1040
1041 label->SetText( wxT( "{" ) + busname + wxT( "}" ) );
1042 label->SetVisible( true );
1043 screen->Append( label );
1044
1045 SHAPE_LINE_CHAIN busLineChain; // to compute nearest segment to bus label
1046
1047 for( const VERTEX& cur : bus.Shape.Vertices )
1048 {
1049 busLineChain.Append( getKiCadPoint( cur.End ) );
1050
1051 if( firstPt )
1052 {
1053 last = cur;
1054 firstPt = false;
1055
1056 if( !bus.HasBusLabel )
1057 {
1058 // Add a bus label on the starting point if the original CADSTAR design
1059 // does not have an explicit label
1060 label->SetPosition( getKiCadPoint( last.End ) );
1061 }
1062
1063 continue;
1064 }
1065
1066
1067 SCH_LINE* kiBus = new SCH_LINE();
1068
1069 kiBus->SetStartPoint( getKiCadPoint( last.End ) );
1070 kiBus->SetEndPoint( getKiCadPoint( cur.End ) );
1071 kiBus->SetLayer( LAYER_BUS );
1072 kiBus->SetLineWidth( getLineThickness( bus.LineCodeID ) );
1073 screen->Append( kiBus );
1074
1075 last = cur;
1076 }
1077
1078 if( bus.HasBusLabel )
1079 {
1080 //lets find the closest point in the busline to the label
1081 VECTOR2I busLabelLoc = getKiCadPoint( bus.BusLabel.Position );
1082 VECTOR2I nearestPt = busLineChain.NearestPoint( busLabelLoc );
1083
1084 label->SetPosition( nearestPt );
1085
1087 bus.BusLabel.Justification );
1088
1089 // Re-set bus name as it might have been "double-escaped" after applyTextSettings
1090 label->SetText( wxT( "{" ) + busname + wxT( "}" ) );
1091
1092 // Note orientation of the bus label will be determined in loadNets
1093 // (the position of the wire will determine how best to place the bus label)
1094 }
1095 }
1096 }
1097}
1098
1099
1101{
1102 for( std::pair<NET_ID, NET_SCH> netPair : Schematic.Nets )
1103 {
1104 NET_SCH net = netPair.second;
1105 wxString netName = net.Name;
1106 std::map<NETELEMENT_ID, SCH_LABEL*> netlabels;
1107
1108 if( netName.IsEmpty() )
1109 netName = wxString::Format( "$%ld", net.SignalNum );
1110
1111 netName = HandleTextOverbar( netName );
1112
1113 for( std::pair<NETELEMENT_ID, NET_SCH::SYM_TERM> terminalPair : net.Terminals )
1114 {
1115 NET_SCH::SYM_TERM netTerm = terminalPair.second;
1116
1117 if( m_powerSymMap.find( netTerm.SymbolID ) != m_powerSymMap.end() )
1118 {
1119 SCH_FIELD* val = m_powerSymMap.at( netTerm.SymbolID )->GetField( FIELD_T::VALUE );
1120 val->SetText( netName );
1121 val->SetBold( false );
1122 val->SetVisible( false );
1123
1124 if( netTerm.HasNetLabel )
1125 {
1126 val->SetVisible( true );
1127 val->SetPosition( getKiCadPoint( netTerm.NetLabel.Position ) );
1128
1129 applyTextSettings( val, netTerm.NetLabel.TextCodeID, netTerm.NetLabel.Alignment,
1130 netTerm.NetLabel.Justification, netTerm.NetLabel.OrientAngle,
1131 netTerm.NetLabel.Mirror );
1132 }
1133 }
1134 else if( m_globalLabelsMap.find( netTerm.SymbolID ) != m_globalLabelsMap.end() )
1135 {
1136 m_globalLabelsMap.at( netTerm.SymbolID )->SetText( netName );
1137
1138 LAYER_ID sheet = Schematic.Symbols.at( netTerm.SymbolID ).LayerID;
1139
1140 if( m_sheetMap.count( sheet ) )
1141 {
1142 SCH_SCREEN* screen = m_sheetMap.at( sheet )->GetScreen();
1143
1144 // autoplace intersheet refs again since we've changed the name
1145 m_globalLabelsMap.at( netTerm.SymbolID )->AutoplaceFields( screen, AUTOPLACE_AUTO );
1146 }
1147 }
1148 else if( !net.Name.IsEmpty() && Schematic.Symbols.count( netTerm.SymbolID )
1149 && netTerm.HasNetLabel )
1150 {
1151 // This is a named net that connects to a schematic symbol pin - we need to put a label
1152 SCH_LABEL* label = new SCH_LABEL();
1153 label->SetText( netName );
1154
1155 POINT pinLocation = getLocationOfNetElement( net, netTerm.ID );
1156 label->SetPosition( getKiCadPoint( pinLocation ) );
1157 label->SetVisible( true );
1158
1159 applyTextSettings( label, netTerm.NetLabel.TextCodeID, netTerm.NetLabel.Alignment,
1160 netTerm.NetLabel.Justification );
1161
1162 netlabels.insert( { netTerm.ID, label } );
1163
1164 LAYER_ID sheet = Schematic.Symbols.at( netTerm.SymbolID ).LayerID;
1165 m_sheetMap.at( sheet )->GetScreen()->Append( label );
1166 }
1167 }
1168
1169 auto getHierarchicalLabel =
1170 [&]( const NETELEMENT_ID& aNode ) -> SCH_HIERLABEL*
1171 {
1172 if( aNode.Contains( "BLKT" ) )
1173 {
1174 NET_SCH::BLOCK_TERM blockTerm = net.BlockTerminals.at( aNode );
1175 BLOCK_PIN_ID blockPinID = std::make_pair( blockTerm.BlockID,
1176 blockTerm.TerminalID );
1177
1178 if( m_sheetPinMap.find( blockPinID ) != m_sheetPinMap.end() )
1179 return m_sheetPinMap.at( blockPinID );
1180 }
1181
1182 return nullptr;
1183 };
1184
1185 //Add net name to all hierarchical pins (block terminals in CADSTAR)
1186 for( std::pair<NETELEMENT_ID, NET_SCH::BLOCK_TERM> blockPair : net.BlockTerminals )
1187 {
1188 SCH_HIERLABEL* label = getHierarchicalLabel( blockPair.first );
1189
1190 if( label )
1191 label->SetText( netName );
1192 }
1193
1194 // Load all bus entries and add net label if required
1195 for( std::pair<NETELEMENT_ID, NET_SCH::BUS_TERM> busPair : net.BusTerminals )
1196 {
1197 NET_SCH::BUS_TERM busTerm = busPair.second;
1198 BUS bus = Schematic.Buses.at( busTerm.BusID );
1199
1200 if( !alg::contains( m_busesMap.at( bus.ID )->Members(), netName ) )
1201 m_busesMap.at( bus.ID )->Members().emplace_back( netName );
1202
1203 SCH_BUS_WIRE_ENTRY* busEntry =
1204 new SCH_BUS_WIRE_ENTRY( getKiCadPoint( busTerm.FirstPoint ), false );
1205
1206 VECTOR2I size =
1207 getKiCadPoint( busTerm.SecondPoint ) - getKiCadPoint( busTerm.FirstPoint );
1208 busEntry->SetSize( VECTOR2I( size.x, size.y ) );
1209
1210 m_sheetMap.at( bus.LayerID )->GetScreen()->Append( busEntry );
1211
1212 // Always add a label at bus terminals to ensure connectivity.
1213 // If the original design does not have a label, just make it very small
1214 // to keep connectivity but make the design look visually similar to
1215 // the original.
1216 SCH_LABEL* label = new SCH_LABEL();
1217 label->SetText( netName );
1218 label->SetPosition( getKiCadPoint( busTerm.SecondPoint ) );
1219 label->SetVisible( true );
1220
1221 if( busTerm.HasNetLabel )
1222 {
1223 applyTextSettings( label, busTerm.NetLabel.TextCodeID, busTerm.NetLabel.Alignment,
1224 busTerm.NetLabel.Justification );
1225 }
1226 else
1227 {
1229 }
1230
1231 netlabels.insert( { busTerm.ID, label } );
1232 m_sheetMap.at( bus.LayerID )->GetScreen()->Append( label );
1233 }
1234
1235 for( std::pair<NETELEMENT_ID, NET_SCH::DANGLER> danglerPair : net.Danglers )
1236 {
1237 NET_SCH::DANGLER dangler = danglerPair.second;
1238
1239 SCH_LABEL* label = new SCH_LABEL();
1240 label->SetPosition( getKiCadPoint( dangler.Position ) );
1241 label->SetVisible( true );
1242
1243 if( dangler.HasNetLabel )
1244 {
1245 applyTextSettings( label, dangler.NetLabel.TextCodeID, dangler.NetLabel.Alignment,
1246 dangler.NetLabel.Justification );
1247 }
1248
1249 label->SetText( netName ); // set text after applying settings to avoid double-escaping
1250 netlabels.insert( { dangler.ID, label } );
1251
1252 m_sheetMap.at( dangler.LayerID )->GetScreen()->Append( label );
1253 }
1254
1255 for( NET_SCH::CONNECTION_SCH conn : net.Connections )
1256 {
1257 if( conn.LayerID == wxT( "NO_SHEET" ) )
1258 continue; // No point loading virtual connections. KiCad handles that internally
1259
1260 POINT start = getLocationOfNetElement( net, conn.StartNode );
1261 POINT end = getLocationOfNetElement( net, conn.EndNode );
1262
1263 if( start.x == UNDEFINED_VALUE || end.x == UNDEFINED_VALUE )
1264 continue;
1265
1266 // Connections in CADSTAR are always implied between symbols even if the route
1267 // doesn't start and end exactly at the connection points
1268 if( conn.Path.size() < 1 || conn.Path.front() != start )
1269 conn.Path.insert( conn.Path.begin(), start );
1270
1271 if( conn.Path.size() < 2 || conn.Path.back() != end )
1272 conn.Path.push_back( end );
1273
1274 bool firstPt = true;
1275 bool secondPt = false;
1276 VECTOR2I last;
1277 SCH_LINE* wire = nullptr;
1278
1279 SHAPE_LINE_CHAIN wireChain; // Create a temp. line chain representing the connection
1280
1281 for( const POINT& pt : conn.Path )
1282 wireChain.Append( getKiCadPoint( pt ) );
1283
1284 // AUTO-FIX SHEET PINS
1285 //--------------------
1286 // KiCad constrains the sheet pin on the edge of the sheet object whereas in
1287 // CADSTAR it can be anywhere. Let's find the intersection of the wires with the sheet
1288 // and place the hierarchical
1289 std::vector<NETELEMENT_ID> nodes;
1290 nodes.push_back( conn.StartNode );
1291 nodes.push_back( conn.EndNode );
1292
1293 for( const NETELEMENT_ID& node : nodes )
1294 {
1295 SCH_HIERLABEL* sheetPin = getHierarchicalLabel( node );
1296
1297 if( sheetPin )
1298 {
1299 if( sheetPin->Type() == SCH_SHEET_PIN_T
1300 && SCH_SHEET::ClassOf( sheetPin->GetParent() ) )
1301 {
1302 SCH_SHEET* parentSheet = static_cast<SCH_SHEET*>( sheetPin->GetParent() );
1303 VECTOR2I sheetSize = parentSheet->GetSize();
1304 VECTOR2I sheetPosition = parentSheet->GetPosition();
1305
1306 int leftSide = sheetPosition.x;
1307 int rightSide = sheetPosition.x + sheetSize.x;
1308 int topSide = sheetPosition.y;
1309 int botSide = sheetPosition.y + sheetSize.y;
1310
1311 SHAPE_LINE_CHAIN sheetEdge;
1312
1313 sheetEdge.Append( leftSide, topSide );
1314 sheetEdge.Append( rightSide, topSide );
1315 sheetEdge.Append( rightSide, botSide );
1316 sheetEdge.Append( leftSide, botSide );
1317 sheetEdge.Append( leftSide, topSide );
1318
1319 SHAPE_LINE_CHAIN::INTERSECTIONS wireToSheetIntersects;
1320
1321 if( !wireChain.Intersect( sheetEdge, wireToSheetIntersects ) )
1322 {
1323 // The block terminal is outside the block shape in the original
1324 // CADSTAR design. Since KiCad's Sheet Pin will already be constrained
1325 // on the edge, we will simply join to it with a straight line.
1326 if( node == conn.StartNode )
1327 wireChain = wireChain.Reverse();
1328
1329 wireChain.Append( sheetPin->GetPosition() );
1330
1331 if( node == conn.StartNode )
1332 wireChain = wireChain.Reverse();
1333 }
1334 else
1335 {
1336 // The block terminal is either inside or on the shape edge. Lets use
1337 // the first intersection point.
1338 VECTOR2I intsctPt = wireToSheetIntersects.at( 0 ).p;
1339 int intsctIndx = wireChain.FindSegment( intsctPt );
1340 wxASSERT_MSG( intsctIndx != -1, "Can't find intersecting segment" );
1341
1342 if( node == conn.StartNode )
1343 wireChain.Replace( 0, intsctIndx, intsctPt );
1344 else
1345 wireChain.Replace( intsctIndx + 1, /*end index*/ -1, intsctPt );
1346
1347 sheetPin->SetPosition( intsctPt );
1348 }
1349 }
1350 }
1351 }
1352
1353 auto fixNetLabelsAndSheetPins =
1354 [&]( const EDA_ANGLE& aWireAngle, NETELEMENT_ID& aNetEleID )
1355 {
1356 SPIN_STYLE spin = getSpinStyle( aWireAngle );
1357
1358 if( netlabels.find( aNetEleID ) != netlabels.end() )
1359 netlabels.at( aNetEleID )->SetSpinStyle( spin.MirrorY() );
1360
1361 SCH_HIERLABEL* sheetPin = getHierarchicalLabel( aNetEleID );
1362
1363 if( sheetPin )
1364 sheetPin->SetSpinStyle( spin.MirrorX() );
1365 };
1366
1367 // Now we can load the wires and fix the label orientations
1368 for( const VECTOR2I& pt : wireChain.CPoints() )
1369 {
1370 if( firstPt )
1371 {
1372 last = pt;
1373 firstPt = false;
1374 secondPt = true;
1375 continue;
1376 }
1377
1378 if( secondPt )
1379 {
1380 secondPt = false;
1381
1382 EDA_ANGLE wireAngle( last - pt );
1383 fixNetLabelsAndSheetPins( wireAngle, conn.StartNode );
1384 }
1385
1386 wire = new SCH_LINE();
1387
1388 wire->SetStartPoint( last );
1389 wire->SetEndPoint( pt );
1390 wire->SetLayer( LAYER_WIRE );
1391
1392 if( !conn.ConnectionLineCode.IsEmpty() )
1393 wire->SetLineWidth( getLineThickness( conn.ConnectionLineCode ) );
1394
1395 last = pt;
1396
1397 m_sheetMap.at( conn.LayerID )->GetScreen()->Append( wire );
1398 }
1399
1400 //Fix labels on the end wire
1401 if( wire )
1402 {
1403 EDA_ANGLE wireAngle( wire->GetEndPoint() - wire->GetStartPoint() );
1404 fixNetLabelsAndSheetPins( wireAngle, conn.EndNode );
1405 }
1406 }
1407
1408 for( std::pair<NETELEMENT_ID, NET_SCH::JUNCTION_SCH> juncPair : net.Junctions )
1409 {
1410 NET_SCH::JUNCTION_SCH junc = juncPair.second;
1411
1412 SCH_JUNCTION* kiJunc = new SCH_JUNCTION();
1413
1414 kiJunc->SetPosition( getKiCadPoint( junc.Location ) );
1415 m_sheetMap.at( junc.LayerID )->GetScreen()->Append( kiJunc );
1416
1417 if( junc.HasNetLabel )
1418 {
1419 // In CADSTAR the label can be placed anywhere, but in KiCad it has to be placed
1420 // in the same location as the junction for it to be connected to it.
1421 SCH_LABEL* label = new SCH_LABEL();
1422 label->SetText( netName );
1423 label->SetPosition( getKiCadPoint( junc.Location ) );
1424 label->SetVisible( true );
1425
1426 EDA_ANGLE labelAngle = getAngle( junc.NetLabel.OrientAngle );
1427 SPIN_STYLE spin = getSpinStyle( labelAngle );
1428
1429 label->SetSpinStyle( spin );
1430
1431 m_sheetMap.at( junc.LayerID )->GetScreen()->Append( label );
1432 }
1433 }
1434 }
1435}
1436
1437
1439{
1440 for( std::pair<FIGURE_ID, FIGURE> figPair : Schematic.Figures )
1441 {
1442 FIGURE fig = figPair.second;
1443
1444 loadFigure( fig, fig.LayerID, LAYER_NOTES );
1445 }
1446}
1447
1448
1450{
1451 for( std::pair<TEXT_ID, TEXT> textPair : Schematic.Texts )
1452 {
1453 TEXT txt = textPair.second;
1454
1455 SCH_TEXT* kiTxt = getKiCadSchText( txt );
1456 loadItemOntoKiCadSheet( txt.LayerID, kiTxt );
1457 }
1458}
1459
1460
1462{
1463 for( std::pair<DOCUMENTATION_SYMBOL_ID, DOCUMENTATION_SYMBOL> docSymPair :
1465 {
1466 DOCUMENTATION_SYMBOL docSym = docSymPair.second;
1467
1468 if( Library.SymbolDefinitions.find( docSym.SymdefID ) == Library.SymbolDefinitions.end() )
1469 {
1470 m_reporter->Report( wxString::Format( _( "Documentation Symbol '%s' refers to symbol "
1471 "definition ID '%s' which does not exist in "
1472 "the library. The symbol was not loaded." ),
1473 docSym.ID,
1474 docSym.SymdefID ),
1476 continue;
1477 }
1478
1479 SYMDEF_SCM docSymDef = Library.SymbolDefinitions.at( docSym.SymdefID );
1480 VECTOR2I moveVector = getKiCadPoint( docSym.Origin ) - getKiCadPoint( docSymDef.Origin );
1481 EDA_ANGLE rotationAngle = getAngle( docSym.OrientAngle );
1482 double scalingFactor = (double) docSym.ScaleRatioNumerator
1483 / (double) docSym.ScaleRatioDenominator;
1484 VECTOR2I centreOfTransform = getKiCadPoint( docSymDef.Origin );
1485 bool mirrorInvert = docSym.Mirror;
1486
1487 for( std::pair<FIGURE_ID, FIGURE> figPair : docSymDef.Figures )
1488 {
1489 FIGURE fig = figPair.second;
1490
1491 loadFigure( fig, docSym.LayerID, LAYER_NOTES, moveVector, rotationAngle, scalingFactor,
1492 centreOfTransform, mirrorInvert );
1493 }
1494
1495 for( std::pair<TEXT_ID, TEXT> textPair : docSymDef.Texts )
1496 {
1497 TEXT txt = textPair.second;
1498
1499 txt.Mirror = ( txt.Mirror ) ? !mirrorInvert : mirrorInvert;
1500 txt.OrientAngle = docSym.OrientAngle - txt.OrientAngle;
1501
1502 SCH_TEXT* kiTxt = getKiCadSchText( txt );
1503
1504 VECTOR2I newPosition = applyTransform( kiTxt->GetPosition(), moveVector, rotationAngle,
1505 scalingFactor, centreOfTransform, mirrorInvert );
1506
1507 int newTxtWidth = KiROUND( kiTxt->GetTextWidth() * scalingFactor );
1508 int newTxtHeight = KiROUND( kiTxt->GetTextHeight() * scalingFactor );
1509 int newTxtThickness = KiROUND( kiTxt->GetTextThickness() * scalingFactor );
1510
1511 kiTxt->SetPosition( newPosition );
1512 kiTxt->SetTextWidth( newTxtWidth );
1513 kiTxt->SetTextHeight( newTxtHeight );
1514 kiTxt->SetTextThickness( newTxtThickness );
1515
1516 loadItemOntoKiCadSheet( docSym.LayerID, kiTxt );
1517 }
1518 }
1519}
1520
1521
1523{
1524 auto findAndReplaceTextField =
1525 [&]( TEXT_FIELD_NAME aField, wxString aValue )
1526 {
1527 if( m_context.TextFieldToValuesMap.find( aField ) != m_context.TextFieldToValuesMap.end() )
1528 {
1529 if( m_context.TextFieldToValuesMap.at( aField ) != aValue )
1530 {
1531 m_context.TextFieldToValuesMap.at( aField ) = aValue;
1532 m_context.InconsistentTextFields.insert( aField );
1533 return false;
1534 }
1535 }
1536 else
1537 {
1538 m_context.TextFieldToValuesMap.insert( { aField, aValue } );
1539 }
1540
1541 return true;
1542 };
1543
1544 PROJECT* pj = &m_schematic->Project();
1545
1546 if( pj )
1547 {
1548 std::map<wxString, wxString>& txtVars = pj->GetTextVars();
1549
1550 // Most of the design text fields can be derived from other elements
1551 if( Schematic.VariantHierarchy.Variants.size() > 0 )
1552 {
1553 VARIANT loadedVar = Schematic.VariantHierarchy.Variants.begin()->second;
1554
1555 findAndReplaceTextField( TEXT_FIELD_NAME::VARIANT_NAME, loadedVar.Name );
1556 findAndReplaceTextField( TEXT_FIELD_NAME::VARIANT_DESCRIPTION, loadedVar.Description );
1557 }
1558
1559 findAndReplaceTextField( TEXT_FIELD_NAME::DESIGN_TITLE, Header.JobTitle );
1560
1561 for( std::pair<TEXT_FIELD_NAME, wxString> txtvalue : m_context.TextFieldToValuesMap )
1562 {
1563 wxString varName = CADSTAR_TO_KICAD_FIELDS.at( txtvalue.first );
1564 wxString varValue = txtvalue.second;
1565
1566 txtVars.insert( { varName, varValue } );
1567 }
1568
1569 for( std::pair<wxString, wxString> txtvalue : m_context.FilenamesToTextMap )
1570 {
1571 wxString varName = txtvalue.first;
1572 wxString varValue = txtvalue.second;
1573
1574 txtVars.insert( { varName, varValue } );
1575 }
1576 }
1577 else
1578 {
1579 m_reporter->Report( _( "Text Variables could not be set as there is no project attached." ),
1581 }
1582}
1583
1584
1585SCH_FIELD*
1587 std::unique_ptr<LIB_SYMBOL>& aKiCadSymbol )
1588{
1589 // First Check if field already exists
1590 if( SCH_FIELD* existingField = aKiCadSymbol->GetField( aFieldName ) )
1591 return existingField;
1592
1593 SCH_FIELD* newfield = new SCH_FIELD( aKiCadSymbol.get(), FIELD_T::USER, aFieldName );
1594 newfield->SetVisible( false );
1595 aKiCadSymbol->AddField( newfield );
1596 /*
1597 @todo we should load that a field is a URL by checking if it starts with "Link"
1598 e.g.:
1599 if( aFieldName.Lower().StartsWith( "link" ) )
1600 newfield->SetAsURL*/
1601
1602 return newfield;
1603}
1604
1605
1607{
1608 wxCHECK( Library.SymbolDefinitions.find( aSymdefID ) != Library.SymbolDefinitions.end(), nullptr );
1609
1610 if( m_symDefMap.count( aSymdefID ) )
1611 return m_symDefMap.at( aSymdefID ).get(); // return a non-owning ptr
1612
1613 SYMDEF_SCM csSym = Library.SymbolDefinitions.at( aSymdefID );
1614 std::unique_ptr<LIB_SYMBOL> kiSym = std::make_unique<LIB_SYMBOL>( csSym.BuildLibName() );
1615 const int gateNumber = 1; // Always load to gate "A" - we will change the unit later
1616
1617 // Load Graphical Figures
1618 for( std::pair<FIGURE_ID, FIGURE> figPair : csSym.Figures )
1619 {
1620 FIGURE fig = figPair.second;
1621 int lineThickness = getLineThickness( fig.LineCodeID );
1622 LINE_STYLE linestyle = getLineStyle( fig.LineCodeID );
1623
1624 if( fig.Shape.Type == SHAPE_TYPE::OPENSHAPE )
1625 {
1626 loadLibrarySymbolShapeVertices( fig.Shape.Vertices, csSym.Origin, kiSym.get(),
1627 gateNumber,
1628 lineThickness );
1629 }
1630 else
1631 {
1632 SCH_SHAPE* shape = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
1633
1635 [&]( const VECTOR2I& aPt )
1636 {
1637 return getKiCadLibraryPoint( aPt, csSym.Origin );
1638 },
1639 ARC_ACCURACY ) );
1640
1641 shape->SetUnit( gateNumber );
1642
1643 shape->SetStroke( STROKE_PARAMS( lineThickness, linestyle ) );
1644
1645 if( fig.Shape.Type == SHAPE_TYPE::SOLID )
1646 shape->SetFillMode( FILL_T::FILLED_SHAPE );
1647 else if( fig.Shape.Type == SHAPE_TYPE::OUTLINE )
1648 shape->SetFillMode( FILL_T::NO_FILL );
1649 else if( fig.Shape.Type == SHAPE_TYPE::HATCHED ) // We don't have an equivalent
1650 shape->SetFillMode( FILL_T::FILLED_WITH_BG_BODYCOLOR );
1651
1652 kiSym->AddDrawItem( shape );
1653 }
1654 }
1655
1656 PINNUM_TO_TERMINAL_MAP pinNumToTerminals;
1657
1658 // Load Pins
1659 for( std::pair<TERMINAL_ID, TERMINAL> termPair : csSym.Terminals )
1660 {
1661 TERMINAL term = termPair.second;
1662 wxString pinNum = wxString::Format( "%ld", term.ID );
1663 wxString pinName = wxEmptyString;
1664 std::unique_ptr<SCH_PIN> pin = std::make_unique<SCH_PIN>( kiSym.get() );
1665
1666 // Assume passive pin for now (we will set it later once we load the parts)
1667 pin->SetType( ELECTRICAL_PINTYPE::PT_PASSIVE );
1668
1669 pin->SetPosition( getKiCadLibraryPoint( term.Position, csSym.Origin ) );
1670 pin->SetLength( 0 ); //CADSTAR Pins are just a point (have no length)
1671 pin->SetShape( GRAPHIC_PINSHAPE::LINE );
1672 pin->SetUnit( gateNumber );
1673 pin->SetNumber( pinNum );
1674 pin->SetName( pinName );
1675
1676 // TC0 is the default CADSTAR text size for name/number if none specified
1677 int pinNumberHeight = getTextHeightFromTextCode( wxT( "TC0" ) );
1678 int pinNameHeight = getTextHeightFromTextCode( wxT( "TC0" ) );
1679
1680 if( csSym.PinNumberLocations.count( term.ID ) )
1681 {
1682 PIN_NUM_LABEL_LOC pinNumLocation = csSym.PinNumberLocations.at( term.ID );
1683 pinNumberHeight = getTextHeightFromTextCode( pinNumLocation.TextCodeID );
1684 }
1685
1686 if( csSym.PinLabelLocations.count( term.ID ) )
1687 {
1688 PIN_NUM_LABEL_LOC pinNameLocation = csSym.PinLabelLocations.at( term.ID );
1689 pinNameHeight = getTextHeightFromTextCode( pinNameLocation.TextCodeID );
1690 }
1691
1692 pin->SetNumberTextSize( pinNumberHeight );
1693 pin->SetNameTextSize( pinNameHeight );
1694
1695 pinNumToTerminals.insert( { pin->GetNumber(), term.ID } );
1696 kiSym->AddDrawItem( pin.release() );
1697 }
1698
1699 m_symDefTerminalsMap.insert( { aSymdefID, pinNumToTerminals } );
1700 fixUpLibraryPins( kiSym.get(), gateNumber );
1701
1702
1703 // Load Text items
1704 for( std::pair<TEXT_ID, TEXT> textPair : csSym.Texts )
1705 {
1706 TEXT csText = textPair.second;
1707 VECTOR2I pos = getKiCadLibraryPoint( csText.Position, csSym.Origin );
1708 auto libtext = std::make_unique<SCH_TEXT>( pos, csText.Text, LAYER_DEVICE );
1709
1710 libtext->SetUnit( gateNumber );
1711 libtext->SetPosition( getKiCadLibraryPoint( csText.Position, csSym.Origin ) );
1712 libtext->SetMultilineAllowed( true ); // temporarily so that we calculate bbox correctly
1713
1714 applyTextSettings( libtext.get(), csText.TextCodeID, csText.Alignment, csText.Justification,
1715 csText.OrientAngle, csText.Mirror );
1716
1717 // Split out multi line text items into individual text elements
1718 if( csText.Text.Contains( "\n" ) )
1719 {
1720 wxArrayString strings;
1721 wxStringSplit( csText.Text, strings, '\n' );
1722
1723 for( size_t ii = 0; ii < strings.size(); ++ii )
1724 {
1725 BOX2I bbox = libtext->GetTextBox( nullptr, ii );
1726 VECTOR2I linePos = { bbox.GetLeft(), -bbox.GetBottom() };
1727
1728 RotatePoint( linePos, libtext->GetTextPos(), -libtext->GetTextAngle() );
1729
1730 SCH_TEXT* textLine = static_cast<SCH_TEXT*>( libtext->Duplicate( IGNORE_PARENT_GROUP ) );
1731 textLine->SetText( strings[ii] );
1734 textLine->SetTextPos( linePos );
1735
1736 // Multiline text not allowed in LIB_TEXT
1737 textLine->SetMultilineAllowed( false );
1738 kiSym->AddDrawItem( textLine );
1739 }
1740 }
1741 else
1742 {
1743 // Multiline text not allowed in LIB_TEXT
1744 libtext->SetMultilineAllowed( false );
1745 kiSym->AddDrawItem( libtext.release() );
1746 }
1747 }
1748
1749 // CADSTAR uses TC1 when fields don't have explicit text/attribute location
1750 static const TEXTCODE_ID defaultTextCode = "TC1";
1751
1752 // Load field locations (Attributes in CADSTAR)
1753
1754 // Symbol name (e.g. R1)
1755 if( csSym.TextLocations.count( SYMBOL_NAME_ATTRID ) )
1756 {
1757 TEXT_LOCATION& textLoc = csSym.TextLocations.at( SYMBOL_NAME_ATTRID );
1758 applyToLibraryFieldAttribute( textLoc, csSym.Origin, &kiSym->GetReferenceField() );
1759 }
1760 else
1761 {
1762 applyTextCodeIfExists( &kiSym->GetReferenceField(), defaultTextCode );
1763 }
1764
1765 // Always add the part name field (even if it doesn't have a specific location defined)
1766 SCH_FIELD* partField = addNewFieldToSymbol( PartNameFieldName, kiSym );
1767 wxCHECK( partField, nullptr );
1768 wxASSERT( partField->GetName() == PartNameFieldName );
1769
1770 if( csSym.TextLocations.count( PART_NAME_ATTRID ) )
1771 {
1772 TEXT_LOCATION& textLoc = csSym.TextLocations.at( PART_NAME_ATTRID );
1773 applyToLibraryFieldAttribute( textLoc, csSym.Origin, partField );
1774 }
1775 else
1776 {
1777 applyTextCodeIfExists( partField, defaultTextCode );
1778 }
1779
1781
1782
1783 for( auto& [attributeId, textLocation] : csSym.TextLocations )
1784 {
1785 if( attributeId == PART_NAME_ATTRID || attributeId == SYMBOL_NAME_ATTRID
1786 || attributeId == SIGNALNAME_ORIGIN_ATTRID || attributeId == LINK_ORIGIN_ATTRID )
1787 {
1788 continue;
1789 }
1790
1791 wxString attributeName = getAttributeName( attributeId );
1792 SCH_FIELD* field = addNewFieldToSymbol( attributeName, kiSym );
1793 applyToLibraryFieldAttribute( textLocation, csSym.Origin, field );
1794 }
1795
1796
1797 for( auto& [attributeId, attrValue] : csSym.AttributeValues )
1798 {
1799 if( attributeId == PART_NAME_ATTRID || attributeId == SYMBOL_NAME_ATTRID
1800 || attributeId == SIGNALNAME_ORIGIN_ATTRID || attributeId == LINK_ORIGIN_ATTRID )
1801 {
1802 continue;
1803 }
1804
1805 wxString attributeName = getAttributeName( attributeId );
1806 SCH_FIELD* field = addNewFieldToSymbol( attributeName, kiSym );
1807
1808 if( attrValue.HasLocation )
1809 applyToLibraryFieldAttribute( attrValue.AttributeLocation, csSym.Origin, field );
1810 else
1811 applyTextCodeIfExists( field, defaultTextCode );
1812 }
1813
1814
1815 m_symDefMap.insert( { aSymdefID, std::move( kiSym ) } );
1816
1817 return m_symDefMap.at( aSymdefID ).get(); // return a non-owning ptr
1818}
1819
1820
1822 const PART& aCadstarPart,
1823 const GATE_ID& aGateID,
1824 LIB_SYMBOL* aSymbol )
1825{
1826 wxCHECK( Library.SymbolDefinitions.find( aSymdefID ) != Library.SymbolDefinitions.end(), /*void*/ );
1827
1828 std::unique_ptr<LIB_SYMBOL> kiSymDef( loadSymdef( aSymdefID )->Duplicate() );
1829 wxCHECK( kiSymDef, /*void*/ );
1830
1831 //todo: need to use unique_ptr more. For now just create it here and release at end of function
1832 std::unique_ptr<LIB_SYMBOL> tempSymbol( aSymbol );
1833
1834 // Update the pin numbers to match those defined in the Cadstar part
1835 TERMINAL_TO_PINNUM_MAP pinNumMap;
1836
1837 for( auto&& [storedPinNum, termID] : m_symDefTerminalsMap[aSymdefID] )
1838 {
1839 PART::DEFINITION::PIN csPin = getPartDefinitionPin( aCadstarPart, aGateID, termID );
1840 SCH_PIN* pin = kiSymDef->GetPin( storedPinNum );
1841
1842 wxString pinName = HandleTextOverbar( csPin.Label );
1843 wxString pinNum = HandleTextOverbar( csPin.Name );
1844
1845 if( pinNum.IsEmpty() )
1846 {
1847 if( !csPin.Identifier.IsEmpty() )
1848 pinNum = csPin.Identifier;
1849 else if( csPin.ID == UNDEFINED_VALUE )
1850 pinNum = wxString::Format( "%ld", termID );
1851 else
1852 pinNum = wxString::Format( "%ld", csPin.ID );
1853 }
1854
1855 pin->SetType( getKiCadPinType( csPin.Type ) );
1856 pin->SetNumber( pinNum );
1857 pin->SetName( pinName );
1858
1859 pinNumMap.insert( { termID, pinNum } );
1860 }
1861
1862 m_pinNumsMap.insert( { aCadstarPart.ID + aGateID, pinNumMap } );
1863
1864 // COPY ITEMS
1865 int gateNumber = getKiCadUnitNumberFromGate( aGateID );
1866 copySymbolItems( kiSymDef, tempSymbol, gateNumber );
1867
1868 // Hide the value field for now (it might get unhidden if an attribute exists in the cadstar
1869 // design with the text "Value"
1870 tempSymbol->GetValueField().SetVisible( false );
1871
1872
1873 if( SCH_FIELD* partNameField = tempSymbol->GetField( PartNameFieldName ) )
1874 partNameField->SetText( EscapeFieldText( aCadstarPart.Name ) );
1875
1876 const POINT& symDefOrigin = Library.SymbolDefinitions.at( aSymdefID ).Origin;
1877 wxString footprintRefName = wxEmptyString;
1878 wxString footprintAlternateName = wxEmptyString;
1879
1880 auto loadLibraryField = [&]( const ATTRIBUTE_VALUE& aAttributeVal )
1881 {
1882 wxString attrName = getAttributeName( aAttributeVal.AttributeID );
1883
1884 // Remove invalid field characters
1885 wxString attributeValue = aAttributeVal.Value;
1886 attributeValue.Replace( wxT( "\n" ), wxT( "\\n" ) );
1887 attributeValue.Replace( wxT( "\r" ), wxT( "\\r" ) );
1888 attributeValue.Replace( wxT( "\t" ), wxT( "\\t" ) );
1889
1890 //TODO: Handle "links": In cadstar a field can be a "link" if its name starts
1891 // with the characters "Link ". Need to figure out how to convert them to
1892 // equivalent in KiCad.
1893
1894 if( attrName == wxT( "(PartDefinitionNameStem)" ) )
1895 {
1896 //Space not allowed in Reference field
1897 attributeValue.Replace( wxT( " " ), "_" );
1898 tempSymbol->GetReferenceField().SetText( attributeValue );
1899 return;
1900 }
1901 else if( attrName == wxT( "(PartDescription)" ) )
1902 {
1903 tempSymbol->SetDescription( attributeValue );
1904 return;
1905 }
1906 else if( attrName == wxT( "(PartDefinitionReferenceName)" ) )
1907 {
1908 footprintRefName = attributeValue;
1909 return;
1910 }
1911 else if( attrName == wxT( "(PartDefinitionAlternateName)" ) )
1912 {
1913 footprintAlternateName = attributeValue;
1914 return;
1915 }
1916
1917 bool attrIsNew = tempSymbol->GetField( attrName ) == nullptr;
1918 SCH_FIELD* attrField = addNewFieldToSymbol( attrName, tempSymbol );
1919
1920 wxASSERT( attrField->GetName() == attrName );
1921 attrField->SetText( aAttributeVal.Value );
1922 attrField->SetUnit( gateNumber );
1923
1924 const ATTRIBUTE_ID& attrid = aAttributeVal.AttributeID;
1925 attrField->SetVisible( isAttributeVisible( attrid ) );
1926
1927 if( aAttributeVal.HasLocation )
1928 {
1929 // Check if the part itself defined a location for the field
1930 applyToLibraryFieldAttribute( aAttributeVal.AttributeLocation, symDefOrigin,
1931 attrField );
1932 }
1933 else if( attrIsNew )
1934 {
1935 attrField->SetVisible( false );
1936 applyTextSettings( attrField, wxT( "TC1" ), ALIGNMENT::NO_ALIGNMENT,
1937 JUSTIFICATION::LEFT, false, true );
1938 }
1939 };
1940
1941 // Load all attributes in the Part Definition
1942 for( auto& [attrId, attrVal] : aCadstarPart.Definition.AttributeValues )
1943 loadLibraryField( attrVal );
1944
1945 // Load all attributes in the Part itself.
1946 for( auto& [attrId, attrVal] : aCadstarPart.AttributeValues )
1947 loadLibraryField( attrVal );
1948
1949 setFootprintOnSymbol( tempSymbol, footprintRefName, footprintAlternateName );
1950
1951 if( aCadstarPart.Definition.HidePinNames )
1952 {
1953 tempSymbol->SetShowPinNames( false );
1954 tempSymbol->SetShowPinNumbers( false );
1955 }
1956
1957 // Update aSymbol just to keep lint happy.
1958 aSymbol = tempSymbol.release();
1959}
1960
1961
1962void CADSTAR_SCH_ARCHIVE_LOADER::setFootprintOnSymbol( std::unique_ptr<LIB_SYMBOL>& aKiCadSymbol,
1963 const wxString& aFootprintName,
1964 const wxString& aFootprintAlternate )
1965{
1966 wxString fpNameInLibrary = generateLibName( aFootprintName, aFootprintAlternate );
1967
1968 if( !fpNameInLibrary.IsEmpty() )
1969 {
1970 wxArrayString fpFilters;
1971 fpFilters.Add( aFootprintName ); // In cadstar one footprint has several "alternates"
1972
1973 if( !aFootprintAlternate.IsEmpty() )
1974 fpFilters.Add( fpNameInLibrary );
1975
1976 aKiCadSymbol->SetFPFilters( fpFilters );
1977
1978 LIB_ID libID( m_footprintLibName, fpNameInLibrary );
1979 aKiCadSymbol->GetFootprintField().SetText( libID.Format() );
1980 }
1981}
1982
1983
1984void CADSTAR_SCH_ARCHIVE_LOADER::loadLibrarySymbolShapeVertices( const std::vector<VERTEX>& aCadstarVertices,
1985 const VECTOR2I& aSymbolOrigin,
1986 LIB_SYMBOL* aSymbol,
1987 int aGateNumber,
1988 int aLineThickness )
1989{
1990 const VERTEX* prev = &aCadstarVertices.at( 0 );
1991 const VERTEX* cur;
1992
1993 wxASSERT_MSG( prev->Type == VERTEX_TYPE::VT_POINT, "First vertex should always be a point." );
1994
1995 for( size_t i = 1; i < aCadstarVertices.size(); i++ )
1996 {
1997 cur = &aCadstarVertices.at( i );
1998
1999 SCH_SHAPE* shape = nullptr;
2000 bool cw = false;
2001 VECTOR2I startPoint = getKiCadLibraryPoint( prev->End, aSymbolOrigin );
2002 VECTOR2I endPoint = getKiCadLibraryPoint( cur->End, aSymbolOrigin );
2003 VECTOR2I centerPoint;
2004
2007 {
2008 centerPoint = ( startPoint + endPoint ) / 2;
2009 }
2010 else
2011 {
2012 centerPoint = getKiCadLibraryPoint( cur->Center, aSymbolOrigin );
2013 }
2014
2015
2016 switch( cur->Type )
2017 {
2019 shape = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2020 shape->AddPoint( startPoint );
2021 shape->AddPoint( endPoint );
2022 break;
2023
2026 cw = true;
2028
2031 shape = new SCH_SHAPE( SHAPE_T::ARC, LAYER_DEVICE );
2032
2033 shape->SetPosition( centerPoint );
2034
2035 if( cw )
2036 {
2037 shape->SetStart( endPoint );
2038 shape->SetEnd( startPoint );
2039 }
2040 else
2041 {
2042 shape->SetStart( startPoint );
2043 shape->SetEnd( endPoint );
2044 }
2045
2046 break;
2047 }
2048
2049 shape->SetUnit( aGateNumber );
2050 shape->SetStroke( STROKE_PARAMS( aLineThickness, LINE_STYLE::SOLID ) );
2051 aSymbol->AddDrawItem( shape, false );
2052
2053 prev = cur;
2054 }
2055
2056 aSymbol->GetDrawItems().sort();
2057}
2058
2059
2061 const VECTOR2I& aSymbolOrigin,
2062 SCH_FIELD* aKiCadField )
2063{
2064 aKiCadField->SetTextPos( getKiCadLibraryPoint( aCadstarAttrLoc.Position, aSymbolOrigin ) );
2065
2066 applyTextSettings( aKiCadField, aCadstarAttrLoc.TextCodeID, aCadstarAttrLoc.Alignment,
2067 aCadstarAttrLoc.Justification, aCadstarAttrLoc.OrientAngle,
2068 aCadstarAttrLoc.Mirror );
2069}
2070
2071
2073 const LIB_SYMBOL& aKiCadPart,
2074 EDA_ANGLE& aComponentOrientation )
2075{
2076 wxString libName = CreateLibName( m_footprintLibName, m_rootSheet );
2077
2078 LIB_ID libId;
2079 libId.SetLibItemName( aKiCadPart.GetName() );
2080 libId.SetLibNickname( libName );
2081
2082 int unit = getKiCadUnitNumberFromGate( aCadstarSymbol.GateID );
2083
2084 SCH_SHEET_PATH sheetpath;
2085 SCH_SHEET* kiSheet = m_sheetMap.at( aCadstarSymbol.LayerID );
2086 m_rootSheet->LocatePathOfScreen( kiSheet->GetScreen(), &sheetpath );
2087
2088 SCH_SYMBOL* symbol = new SCH_SYMBOL( aKiCadPart, libId, &sheetpath, unit );
2089
2090 if( aCadstarSymbol.IsComponent )
2091 symbol->SetRef( &sheetpath, aCadstarSymbol.ComponentRef.Designator );
2092
2093 symbol->SetPosition( getKiCadPoint( aCadstarSymbol.Origin ) );
2094
2095 EDA_ANGLE compAngle = getAngle( aCadstarSymbol.OrientAngle );
2096 int compOrientation = 0;
2097
2098 if( aCadstarSymbol.Mirror )
2099 {
2100 compAngle = -compAngle;
2101 compOrientation += SYMBOL_ORIENTATION_T::SYM_MIRROR_Y;
2102 }
2103
2104 compOrientation += getComponentOrientation( compAngle, aComponentOrientation );
2105 EDA_ANGLE test1( compAngle );
2106 EDA_ANGLE test2( aComponentOrientation );
2107
2108 if( test1.Normalize180() != test2.Normalize180() )
2109 {
2110 m_reporter->Report( wxString::Format( _( "Symbol '%s' is rotated by an angle of %.1f " //format:allow
2111 "degrees in the original CADSTAR design but "
2112 "KiCad only supports rotation angles multiples "
2113 "of 90 degrees. The connecting wires will need "
2114 "manual fixing." ),
2115 aCadstarSymbol.ComponentRef.Designator,
2116 compAngle.AsDegrees() ),
2118 }
2119
2120 symbol->SetOrientation( compOrientation );
2121
2122 if( m_sheetMap.find( aCadstarSymbol.LayerID ) == m_sheetMap.end() )
2123 {
2124 m_reporter->Report( wxString::Format( _( "Symbol '%s' references sheet ID '%s' which does "
2125 "not exist in the design. The symbol was not "
2126 "loaded." ),
2127 aCadstarSymbol.ComponentRef.Designator,
2128 aCadstarSymbol.LayerID ),
2130
2131 delete symbol;
2132 return nullptr;
2133 }
2134
2135 wxString gate = ( aCadstarSymbol.GateID.IsEmpty() ) ? wxString( wxT( "A" ) ) : aCadstarSymbol.GateID;
2136 wxString partGateIndex = aCadstarSymbol.PartRef.RefID + gate;
2137
2138 //Handle pin swaps
2139 if( m_pinNumsMap.find( partGateIndex ) != m_pinNumsMap.end() )
2140 {
2141 TERMINAL_TO_PINNUM_MAP termNumMap = m_pinNumsMap.at( partGateIndex );
2142
2143 std::map<wxString, SCH_PIN*> pinNumToLibPinMap;
2144
2145 for( auto& term : termNumMap )
2146 {
2147 wxString pinNum = term.second;
2148 pinNumToLibPinMap.insert( { pinNum,
2149 symbol->GetLibSymbolRef()->GetPin( term.second ) } );
2150 }
2151
2152 auto replacePinNumber =
2153 [&]( wxString aOldPinNum, wxString aNewPinNum )
2154 {
2155 if( aOldPinNum == aNewPinNum )
2156 return;
2157
2158 SCH_PIN* libpin = pinNumToLibPinMap.at( aOldPinNum );
2159 libpin->SetNumber( HandleTextOverbar( aNewPinNum ) );
2160 };
2161
2162 //Older versions of Cadstar used pin numbers
2163 for( auto& pinPair : aCadstarSymbol.PinNumbers )
2164 {
2165 SYMBOL::PIN_NUM pin = pinPair.second;
2166
2167 replacePinNumber( termNumMap.at( pin.TerminalID ),
2168 wxString::Format( "%ld", pin.PinNum ) );
2169 }
2170
2171 //Newer versions of Cadstar use pin names
2172 for( auto& pinPair : aCadstarSymbol.PinNames )
2173 {
2174 SYMPINNAME_LABEL pin = pinPair.second;
2175 replacePinNumber( termNumMap.at( pin.TerminalID ), pin.NameOrLabel );
2176 }
2177
2178 symbol->UpdatePins();
2179 }
2180
2181 kiSheet->GetScreen()->Append( symbol );
2182
2183 return symbol;
2184}
2185
2186
2188 const EDA_ANGLE& aComponentOrientation,
2189 bool aIsMirrored,
2190 SCH_FIELD* aKiCadField )
2191{
2192 aKiCadField->SetPosition( getKiCadPoint( aCadstarAttrLoc.Position ) );
2193 aKiCadField->SetVisible( true );
2194
2195 ALIGNMENT alignment = aCadstarAttrLoc.Alignment;
2196 EDA_ANGLE textAngle = getAngle( aCadstarAttrLoc.OrientAngle );
2197
2198 if( aIsMirrored )
2199 {
2200 // We need to change the aligment when the symbol is mirrored based on the text orientation
2201 // To ensure the anchor point is the same in KiCad.
2202
2203 int textIsVertical = KiROUND( textAngle.AsDegrees() / 90.0 ) % 2;
2204
2205 if( textIsVertical )
2206 alignment = rotate180( alignment );
2207
2208 alignment = mirrorX( alignment );
2209 }
2210
2211 applyTextSettings( aKiCadField, aCadstarAttrLoc.TextCodeID, alignment,
2212 aCadstarAttrLoc.Justification,
2213 getCadstarAngle( textAngle - aComponentOrientation ),
2214 aCadstarAttrLoc.Mirror );
2215}
2216
2217
2219 EDA_ANGLE& aReturnedOrientation )
2220{
2221 int compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_0;
2222
2223 EDA_ANGLE oDeg = aOrientAngle;
2224 oDeg.Normalize180();
2225
2226 if( oDeg >= -ANGLE_45 && oDeg <= ANGLE_45 )
2227 {
2228 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_0;
2229 aReturnedOrientation = ANGLE_0;
2230 }
2231 else if( oDeg >= ANGLE_45 && oDeg <= ANGLE_135 )
2232 {
2233 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_90;
2234 aReturnedOrientation = ANGLE_90;
2235 }
2236 else if( oDeg >= ANGLE_135 || oDeg <= -ANGLE_135 )
2237 {
2238 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_180;
2239 aReturnedOrientation = ANGLE_180;
2240 }
2241 else
2242 {
2243 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_270;
2244 aReturnedOrientation = ANGLE_270;
2245 }
2246
2247 return compOrientation;
2248}
2249
2250
2253 const NETELEMENT_ID& aNetElementID )
2254{
2255 // clang-format off
2256 auto logUnknownNetElementError =
2257 [&]()
2258 {
2259 m_reporter->Report( wxString::Format( _( "Net %s references unknown net element %s. "
2260 "The net was not properly loaded and may "
2261 "require manual fixing." ),
2262 getNetName( aNet ),
2263 aNetElementID ),
2265
2266 return POINT();
2267 };
2268 // clang-format on
2269
2270 if( aNetElementID.Contains( "J" ) ) // Junction
2271 {
2272 if( aNet.Junctions.find( aNetElementID ) == aNet.Junctions.end() )
2273 return logUnknownNetElementError();
2274
2275 return aNet.Junctions.at( aNetElementID ).Location;
2276 }
2277 else if( aNetElementID.Contains( "P" ) ) // Terminal/Pin of a symbol
2278 {
2279 if( aNet.Terminals.find( aNetElementID ) == aNet.Terminals.end() )
2280 return logUnknownNetElementError();
2281
2282 SYMBOL_ID symid = aNet.Terminals.at( aNetElementID ).SymbolID;
2283 TERMINAL_ID termid = aNet.Terminals.at( aNetElementID ).TerminalID;
2284
2285 if( Schematic.Symbols.find( symid ) == Schematic.Symbols.end() )
2286 return logUnknownNetElementError();
2287
2288 SYMBOL sym = Schematic.Symbols.at( symid );
2289 SYMDEF_ID symdefid = sym.SymdefID;
2290 VECTOR2I symbolOrigin = sym.Origin;
2291
2292 if( Library.SymbolDefinitions.find( symdefid ) == Library.SymbolDefinitions.end() )
2293 return logUnknownNetElementError();
2294
2295 VECTOR2I libpinPosition =
2296 Library.SymbolDefinitions.at( symdefid ).Terminals.at( termid ).Position;
2297 VECTOR2I libOrigin = Library.SymbolDefinitions.at( symdefid ).Origin;
2298
2299 VECTOR2I pinOffset = libpinPosition - libOrigin;
2300 pinOffset.x = ( pinOffset.x * sym.ScaleRatioNumerator ) / sym.ScaleRatioDenominator;
2301 pinOffset.y = ( pinOffset.y * sym.ScaleRatioNumerator ) / sym.ScaleRatioDenominator;
2302
2303 VECTOR2I pinPosition = symbolOrigin + pinOffset;
2304 EDA_ANGLE compAngle = getAngle( sym.OrientAngle );
2305
2306 if( sym.Mirror )
2307 pinPosition.x = ( 2 * symbolOrigin.x ) - pinPosition.x;
2308
2309 EDA_ANGLE adjustedOrientation;
2310 getComponentOrientation( compAngle, adjustedOrientation );
2311
2312 RotatePoint( pinPosition, symbolOrigin, -adjustedOrientation );
2313
2314 POINT retval;
2315 retval.x = pinPosition.x;
2316 retval.y = pinPosition.y;
2317
2318 return retval;
2319 }
2320 else if( aNetElementID.Contains( "BT" ) ) // Bus Terminal
2321 {
2322 if( aNet.BusTerminals.find( aNetElementID ) == aNet.BusTerminals.end() )
2323 return logUnknownNetElementError();
2324
2325 return aNet.BusTerminals.at( aNetElementID ).SecondPoint;
2326 }
2327 else if( aNetElementID.Contains( "BLKT" ) ) // Block Terminal (sheet hierarchy connection)
2328 {
2329 if( aNet.BlockTerminals.find( aNetElementID ) == aNet.BlockTerminals.end() )
2330 return logUnknownNetElementError();
2331
2332 BLOCK_ID blockid = aNet.BlockTerminals.at( aNetElementID ).BlockID;
2333 TERMINAL_ID termid = aNet.BlockTerminals.at( aNetElementID ).TerminalID;
2334
2335 if( Schematic.Blocks.find( blockid ) == Schematic.Blocks.end() )
2336 return logUnknownNetElementError();
2337
2338 return Schematic.Blocks.at( blockid ).Terminals.at( termid ).Position;
2339 }
2340 else if( aNetElementID.Contains( "D" ) ) // Dangler
2341 {
2342 if( aNet.Danglers.find( aNetElementID ) == aNet.Danglers.end() )
2343 return logUnknownNetElementError();
2344
2345 return aNet.Danglers.at( aNetElementID ).Position;
2346 }
2347 else
2348 {
2349 return logUnknownNetElementError();
2350 }
2351}
2352
2353
2355{
2356 wxString netname = aNet.Name;
2357
2358 if( netname.IsEmpty() )
2359 netname = wxString::Format( "$%ld", aNet.SignalNum );
2360
2361 return netname;
2362}
2363
2364
2365void CADSTAR_SCH_ARCHIVE_LOADER::loadShapeVertices( const std::vector<VERTEX>& aCadstarVertices,
2366 LINECODE_ID aCadstarLineCodeID,
2367 LAYER_ID aCadstarSheetID,
2368 SCH_LAYER_ID aKiCadSchLayerID,
2369 const VECTOR2I& aMoveVector,
2370 const EDA_ANGLE& aRotation,
2371 const double& aScalingFactor,
2372 const VECTOR2I& aTransformCentre,
2373 const bool& aMirrorInvert )
2374{
2375 int lineWidth = KiROUND( getLineThickness( aCadstarLineCodeID ) * aScalingFactor );
2376 LINE_STYLE lineStyle = getLineStyle( aCadstarLineCodeID );
2377
2378 const VERTEX* prev = &aCadstarVertices.at( 0 );
2379 const VERTEX* cur;
2380
2381 wxASSERT_MSG( prev->Type == VERTEX_TYPE::VT_POINT,
2382 "First vertex should always be a point vertex" );
2383
2384 auto pointTransform =
2385 [&]( const VECTOR2I& aV )
2386 {
2387 return applyTransform( getKiCadPoint( aV ), aMoveVector, aRotation,
2388 aScalingFactor, aTransformCentre, aMirrorInvert );
2389 };
2390
2391 for( size_t ii = 1; ii < aCadstarVertices.size(); ii++ )
2392 {
2393 cur = &aCadstarVertices.at( ii );
2394
2395 VECTOR2I transformedStartPoint = pointTransform( prev->End );
2396 VECTOR2I transformedEndPoint = pointTransform( cur->End );
2397
2398 switch( cur->Type )
2399 {
2404 {
2405 SHAPE_ARC tempArc = cur->BuildArc( transformedStartPoint, pointTransform );
2406
2407 SCH_SHAPE* arcShape = new SCH_SHAPE( SHAPE_T::ARC, LAYER_NOTES, lineWidth );
2408 arcShape->SetArcGeometry( tempArc.GetP0(), tempArc.GetArcMid(), tempArc.GetP1() );
2409
2410 loadItemOntoKiCadSheet( aCadstarSheetID, arcShape );
2411 break;
2412 }
2413
2415 {
2416 SCH_LINE* segment = new SCH_LINE();
2417
2418 segment->SetLayer( aKiCadSchLayerID );
2419 segment->SetLineWidth( lineWidth );
2420 segment->SetLineStyle( lineStyle );
2421
2422 segment->SetStartPoint( transformedStartPoint );
2423 segment->SetEndPoint( transformedEndPoint );
2424
2425 loadItemOntoKiCadSheet( aCadstarSheetID, segment );
2426 break;
2427 }
2428
2429 default:
2430 wxFAIL_MSG( "Unknown CADSTAR Vertex type" );
2431 }
2432
2433 prev = cur;
2434 }
2435}
2436
2437
2439 const LAYER_ID& aCadstarSheetIDOverride,
2440 SCH_LAYER_ID aKiCadSchLayerID,
2441 const VECTOR2I& aMoveVector,
2442 const EDA_ANGLE& aRotation,
2443 const double& aScalingFactor,
2444 const VECTOR2I& aTransformCentre,
2445 const bool& aMirrorInvert )
2446{
2447 loadShapeVertices( aCadstarFigure.Shape.Vertices, aCadstarFigure.LineCodeID,
2448 aCadstarSheetIDOverride, aKiCadSchLayerID, aMoveVector, aRotation,
2449 aScalingFactor, aTransformCentre, aMirrorInvert );
2450
2451 for( const CUTOUT& cutout : aCadstarFigure.Shape.Cutouts )
2452 {
2453 loadShapeVertices( cutout.Vertices, aCadstarFigure.LineCodeID, aCadstarSheetIDOverride,
2454 aKiCadSchLayerID, aMoveVector, aRotation, aScalingFactor,
2455 aTransformCentre, aMirrorInvert );
2456 }
2457}
2458
2459
2461 const VECTOR2I& aPosition,
2462 const VECTOR2I& aSheetSize,
2463 const SCH_SHEET_PATH& aParentSheet )
2464{
2465 wxCHECK_MSG( m_sheetMap.find( aCadstarSheetID ) == m_sheetMap.end(), ,
2466 "Sheet already loaded!" );
2467
2468 SCH_SHEET* sheet = new SCH_SHEET(
2469 /* aParent */ aParentSheet.Last(),
2470 /* aPosition */ aPosition,
2471 /* aSize */ VECTOR2I( aSheetSize ) );
2472 SCH_SCREEN* screen = new SCH_SCREEN( m_schematic );
2473 SCH_SHEET_PATH instance( aParentSheet );
2474
2475 sheet->SetScreen( screen );
2476
2477 wxString name = Sheets.SheetNames.at( aCadstarSheetID );
2478
2479 sheet->GetField( FIELD_T::SHEET_NAME )->SetText( name );
2480
2481 int sheetNum = getSheetNumber( aCadstarSheetID );
2482 wxString loadedFilename = wxFileName( Filename ).GetName();
2483 std::string filename = wxString::Format( "%s_%02d", loadedFilename, sheetNum ).ToStdString();
2484
2485 ReplaceIllegalFileNameChars( &filename );
2486 filename += wxT( "." ) + wxString( FILEEXT::KiCadSchematicFileExtension );
2487
2488 sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( filename );
2489
2490 wxFileName fn( m_schematic->Project().GetProjectPath() + filename );
2491 sheet->GetScreen()->SetFileName( fn.GetFullPath() );
2492 aParentSheet.Last()->GetScreen()->Append( sheet );
2493 instance.push_back( sheet );
2494
2495 wxString pageNumStr = wxString::Format( "%d", getSheetNumber( aCadstarSheetID ) );
2496 instance.SetPageNumber( pageNumStr );
2497
2498 sheet->AutoplaceFields( nullptr, AUTOPLACE_AUTO );
2499
2500 m_sheetMap.insert( { aCadstarSheetID, sheet } );
2501
2502 loadChildSheets( aCadstarSheetID, instance );
2503}
2504
2505
2507 const SCH_SHEET_PATH& aSheet )
2508{
2509 wxCHECK_MSG( m_sheetMap.find( aCadstarSheetID ) != m_sheetMap.end(), ,
2510 "FIXME! Parent sheet should be loaded before attempting to load subsheets" );
2511
2512 for( std::pair<BLOCK_ID, BLOCK> blockPair : Schematic.Blocks )
2513 {
2514 BLOCK& block = blockPair.second;
2515
2516 if( block.LayerID == aCadstarSheetID && block.Type == BLOCK::TYPE::CHILD )
2517 {
2518 if( block.AssocLayerID == wxT( "NO_LINK" ) )
2519 {
2520 if( block.Figures.size() > 0 )
2521 {
2522 m_reporter->Report( wxString::Format( _( "The block ID %s (Block name: '%s') "
2523 "is drawn on sheet '%s' but is not "
2524 "linked to another sheet in the "
2525 "design. KiCad requires all sheet "
2526 "symbols to be associated to a sheet, "
2527 "so the block was not loaded." ),
2528 block.ID, block.Name,
2529 Sheets.SheetNames.at( aCadstarSheetID ) ),
2531 }
2532
2533 continue;
2534 }
2535
2536 // In KiCad you can only draw rectangular shapes whereas in Cadstar arbitrary shapes
2537 // are allowed. We will calculate the extents of the Cadstar shape and draw a rectangle
2538
2539 std::pair<VECTOR2I, VECTOR2I> blockExtents;
2540
2541 if( block.Figures.size() > 0 )
2542 {
2543 blockExtents = getFigureExtentsKiCad( block.Figures.begin()->second );
2544 }
2545 else
2546 {
2547 THROW_IO_ERROR( wxString::Format( _( "The CADSTAR schematic might be corrupt: "
2548 "Block %s references a child sheet but has no "
2549 "Figure defined." ),
2550 block.ID ) );
2551 }
2552
2553 loadSheetAndChildSheets( block.AssocLayerID, blockExtents.first, blockExtents.second,
2554 aSheet );
2555
2556 // Hide all KiCad sheet properties (sheet name/filename is not applicable in CADSTAR)
2557 SCH_SHEET* loadedSheet = m_sheetMap.at( block.AssocLayerID );
2558 SCH_FIELDS fields = loadedSheet->GetFields();
2559
2560 for( SCH_FIELD& field : fields )
2561 {
2562 field.SetVisible( false );
2563 }
2564
2565 if( block.HasBlockLabel )
2566 {
2567 //@todo use below code when KiCad supports multi-line fields
2568 /*
2569 // Add the block label as a separate field
2570 SCH_FIELD blockNameField( getKiCadPoint( block.BlockLabel.Position ), 2,
2571 loadedSheet, wxString( "Block name" ) );
2572 blockNameField.SetText( block.Name );
2573 blockNameField.SetVisible( true );
2574
2575 applyTextSettings( &blockNameField,
2576 block.BlockLabel.TextCodeID,
2577 block.BlockLabel.Alignment,
2578 block.BlockLabel.Justification,
2579 block.BlockLabel.OrientAngle,
2580 block.BlockLabel.Mirror );
2581
2582 fields.push_back( blockNameField );*/
2583
2584 // For now as as a text item (supports multi-line properly)
2585 SCH_TEXT* kiTxt = new SCH_TEXT();
2586
2587 kiTxt->SetParent( m_schematic );
2588 kiTxt->SetPosition( getKiCadPoint( block.BlockLabel.Position ) );
2589 kiTxt->SetText( block.Name );
2590
2593 block.BlockLabel.Mirror );
2594
2595 loadItemOntoKiCadSheet( aCadstarSheetID, kiTxt );
2596 }
2597
2598 loadedSheet->SetFields( fields );
2599 }
2600 }
2601}
2602
2603
2604std::vector<CADSTAR_SCH_ARCHIVE_LOADER::LAYER_ID> CADSTAR_SCH_ARCHIVE_LOADER::findOrphanSheets()
2605{
2606 std::vector<LAYER_ID> childSheets, orphanSheets;
2607
2608 //Find all sheets that are child of another
2609 for( std::pair<BLOCK_ID, BLOCK> blockPair : Schematic.Blocks )
2610 {
2611 BLOCK& block = blockPair.second;
2612 LAYER_ID& assocSheetID = block.AssocLayerID;
2613
2614 if( block.Type == BLOCK::TYPE::CHILD )
2615 childSheets.push_back( assocSheetID );
2616 }
2617
2618 //Add sheets that do not have a parent
2619 for( const LAYER_ID& sheetID : Sheets.SheetOrder )
2620 {
2621 if( std::find( childSheets.begin(), childSheets.end(), sheetID ) == childSheets.end() )
2622 orphanSheets.push_back( sheetID );
2623 }
2624
2625 return orphanSheets;
2626}
2627
2628
2630{
2631 int i = 1;
2632
2633 for( const LAYER_ID& sheetID : Sheets.SheetOrder )
2634 {
2635 if( sheetID == aCadstarSheetID )
2636 return i;
2637
2638 ++i;
2639 }
2640
2641 return -1;
2642}
2643
2644
2646 SCH_ITEM* aItem )
2647{
2648 wxCHECK_MSG( aItem, /*void*/, wxT( "aItem is null" ) );
2649
2650 if( aCadstarSheetID == "ALL_SHEETS" )
2651 {
2652 SCH_ITEM* duplicateItem = nullptr;
2653
2654 for( std::pair<LAYER_ID, SHEET_NAME> sheetPair : Sheets.SheetNames )
2655 {
2656 LAYER_ID sheetID = sheetPair.first;
2657 duplicateItem = aItem->Duplicate( IGNORE_PARENT_GROUP );
2658 m_sheetMap.at( sheetID )->GetScreen()->Append( aItem->Duplicate( IGNORE_PARENT_GROUP ) );
2659 }
2660
2661 //Get rid of the extra copy:
2662 delete aItem;
2663 aItem = duplicateItem;
2664 }
2665 else if( aCadstarSheetID == "NO_SHEET" )
2666 {
2667 wxFAIL_MSG( wxT( "Trying to add an item to NO_SHEET? This might be a documentation symbol." ) );
2668 }
2669 else
2670 {
2671 if( m_sheetMap.find( aCadstarSheetID ) != m_sheetMap.end() )
2672 {
2673 m_sheetMap.at( aCadstarSheetID )->GetScreen()->Append( aItem );
2674 }
2675 else
2676 {
2677 delete aItem;
2678 wxFAIL_MSG( wxT( "Unknown Sheet ID." ) );
2679 }
2680 }
2681}
2682
2683
2686 const wxString& aSymDefAlternate )
2687{
2688 if( m_SymDefNamesCache.size() != Library.SymbolDefinitions.size() )
2689 {
2690 // Re-initialise
2691 m_SymDefNamesCache.clear();
2693
2694 // Create a lower case cache to avoid searching each time
2695 for( auto& [id, symdef] : Library.SymbolDefinitions )
2696 {
2697 wxString refKey = symdef.ReferenceName.Lower();
2698 wxString altKey = symdef.Alternate.Lower();
2699
2700 m_SymDefNamesCache[{ refKey, altKey }] = id;
2701
2702 // Secondary cache to find symbols just by the Name (e.g. if the alternate
2703 // does not exist, we still want to return a symbo - the same behaviour
2704 // as CADSTAR
2705
2706 if( !m_DefaultSymDefNamesCache.count( refKey ) )
2707 {
2708 m_DefaultSymDefNamesCache.insert( { refKey, id } );
2709 }
2710 else if( altKey.IsEmpty() )
2711 {
2712 // Always use the empty alternate if it exists
2713 m_DefaultSymDefNamesCache[refKey] = id;
2714 }
2715 }
2716 }
2717
2718 wxString refKeyToFind = aSymdefName.Lower();
2719 wxString altKeyToFind = aSymDefAlternate.Lower();
2720
2721 if( m_SymDefNamesCache.count( { refKeyToFind, altKeyToFind } ) )
2722 {
2723 return m_SymDefNamesCache[{ refKeyToFind, altKeyToFind }];
2724 }
2725 else if( m_DefaultSymDefNamesCache.count( refKeyToFind ) )
2726 {
2727 return m_DefaultSymDefNamesCache[refKeyToFind];
2728 }
2729
2730 return SYMDEF_ID();
2731}
2732
2733
2735{
2736 // Use CADSTAR visibility settings to determine if an attribute is visible
2737 if( AttrColors.AttributeColors.find( aCadstarAttributeID ) != AttrColors.AttributeColors.end() )
2738 return AttrColors.AttributeColors.at( aCadstarAttributeID ).IsVisible;
2739
2740 return false; // If there is no visibility setting, assume not displayed
2741}
2742
2743
2745{
2746 wxCHECK( Assignments.Codedefs.LineCodes.find( aCadstarLineCodeID )
2749
2750 return getKiCadLength( Assignments.Codedefs.LineCodes.at( aCadstarLineCodeID ).Width );
2751}
2752
2753
2755{
2756 wxCHECK( Assignments.Codedefs.LineCodes.find( aCadstarLineCodeID )
2758 LINE_STYLE::SOLID );
2759
2760 // clang-format off
2761 switch( Assignments.Codedefs.LineCodes.at( aCadstarLineCodeID ).Style )
2762 {
2763 case LINESTYLE::DASH: return LINE_STYLE::DASH;
2764 case LINESTYLE::DASHDOT: return LINE_STYLE::DASHDOT;
2765 case LINESTYLE::DASHDOTDOT: return LINE_STYLE::DASHDOT; //TODO: update in future
2766 case LINESTYLE::DOT: return LINE_STYLE::DOT;
2767 case LINESTYLE::SOLID: return LINE_STYLE::SOLID;
2768 default: return LINE_STYLE::DEFAULT;
2769 }
2770 // clang-format on
2771}
2772
2773
2776{
2777 wxCHECK( Assignments.Codedefs.TextCodes.find( aCadstarTextCodeID )
2779 TEXTCODE() );
2780
2781 return Assignments.Codedefs.TextCodes.at( aCadstarTextCodeID );
2782}
2783
2784
2786{
2787 TEXTCODE txtCode = getTextCode( aCadstarTextCodeID );
2788
2789 return KiROUND( (double) getKiCadLength( txtCode.Height ) * TXT_HEIGHT_RATIO );
2790}
2791
2792
2794{
2795 wxCHECK( Assignments.Codedefs.AttributeNames.find( aCadstarAttributeID )
2797 aCadstarAttributeID );
2798
2799 return Assignments.Codedefs.AttributeNames.at( aCadstarAttributeID ).Name;
2800}
2801
2802
2805{
2806 wxCHECK( Parts.PartDefinitions.find( aCadstarPartID ) != Parts.PartDefinitions.end(), PART() );
2807
2808 return Parts.PartDefinitions.at( aCadstarPartID );
2809}
2810
2811
2814{
2815 wxCHECK( Assignments.Codedefs.RouteCodes.find( aCadstarRouteCodeID )
2817 ROUTECODE() );
2818
2819 return Assignments.Codedefs.RouteCodes.at( aCadstarRouteCodeID );
2820}
2821
2822
2823CADSTAR_SCH_ARCHIVE_LOADER::PART::DEFINITION::PIN
2825 const TERMINAL_ID& aTerminalID )
2826{
2827 for( std::pair<PART_DEFINITION_PIN_ID, PART::DEFINITION::PIN> pinPair :
2828 aCadstarPart.Definition.Pins )
2829 {
2830 PART::DEFINITION::PIN partPin = pinPair.second;
2831
2832 if( partPin.TerminalGate == aGateID && partPin.TerminalPin == aTerminalID )
2833 return partPin;
2834 }
2835
2836 return PART::DEFINITION::PIN();
2837}
2838
2839
2841{
2842 switch( aPinType )
2843 {
2844 case CADSTAR_PIN_TYPE::UNCOMMITTED: return ELECTRICAL_PINTYPE::PT_PASSIVE;
2845 case CADSTAR_PIN_TYPE::PIN_INPUT: return ELECTRICAL_PINTYPE::PT_INPUT;
2846 case CADSTAR_PIN_TYPE::OUTPUT_OR: return ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR;
2847 case CADSTAR_PIN_TYPE::OUTPUT_NOT_OR: return ELECTRICAL_PINTYPE::PT_OUTPUT;
2848 case CADSTAR_PIN_TYPE::OUTPUT_NOT_NORM_OR: return ELECTRICAL_PINTYPE::PT_OUTPUT;
2849 case CADSTAR_PIN_TYPE::POWER: return ELECTRICAL_PINTYPE::PT_POWER_IN;
2850 case CADSTAR_PIN_TYPE::GROUND: return ELECTRICAL_PINTYPE::PT_POWER_IN;
2851 case CADSTAR_PIN_TYPE::TRISTATE_BIDIR: return ELECTRICAL_PINTYPE::PT_BIDI;
2852 case CADSTAR_PIN_TYPE::TRISTATE_INPUT: return ELECTRICAL_PINTYPE::PT_INPUT;
2853 case CADSTAR_PIN_TYPE::TRISTATE_DRIVER: return ELECTRICAL_PINTYPE::PT_OUTPUT;
2854 }
2855
2856 return ELECTRICAL_PINTYPE::PT_UNSPECIFIED;
2857}
2858
2860{
2861 if( aCadstarGateID.IsEmpty() )
2862 return 1;
2863
2864 return (int) aCadstarGateID.Upper().GetChar( 0 ) - (int) wxUniChar( 'A' ) + 1;
2865}
2866
2867
2868SPIN_STYLE CADSTAR_SCH_ARCHIVE_LOADER::getSpinStyle( const long long& aCadstarOrientation,
2869 bool aMirror )
2870{
2871 EDA_ANGLE orientation = getAngle( aCadstarOrientation );
2872 SPIN_STYLE spinStyle = getSpinStyle( orientation );
2873
2874 if( aMirror )
2875 {
2876 spinStyle = spinStyle.RotateCCW();
2877 spinStyle = spinStyle.RotateCCW();
2878 }
2879
2880 return spinStyle;
2881}
2882
2883
2885{
2886 SPIN_STYLE spinStyle = SPIN_STYLE::LEFT;
2887
2888 EDA_ANGLE oDeg = aOrientation;
2889 oDeg.Normalize180();
2890
2891 if( oDeg >= -ANGLE_45 && oDeg <= ANGLE_45 )
2892 spinStyle = SPIN_STYLE::RIGHT; // 0deg
2893 else if( oDeg >= ANGLE_45 && oDeg <= ANGLE_135 )
2894 spinStyle = SPIN_STYLE::UP; // 90deg
2895 else if( oDeg >= ANGLE_135 || oDeg <= -ANGLE_135 )
2896 spinStyle = SPIN_STYLE::LEFT; // 180deg
2897 else
2898 spinStyle = SPIN_STYLE::BOTTOM; // 270deg
2899
2900 return spinStyle;
2901}
2902
2903
2906{
2907 switch( aCadstarAlignment )
2908 {
2909 // Change left to right:
2914
2915 //Change right to left:
2919
2920 // Center alignment does not mirror:
2923 case ALIGNMENT::TOPCENTER: return aCadstarAlignment;
2924
2925 // Shouldn't be here
2926 default: wxFAIL_MSG( "Unknown Cadstar Alignment" ); return aCadstarAlignment;
2927 }
2928}
2929
2930
2933{
2934 switch( aCadstarAlignment )
2935 {
2946
2947 // Shouldn't be here
2948 default: wxFAIL_MSG( "Unknown Cadstar Alignment" ); return aCadstarAlignment;
2949 }
2950}
2951
2952
2954 const TEXTCODE_ID& aCadstarTextCodeID )
2955{
2956 // Ensure we have no Cadstar overbar characters
2957 wxString escapedText = HandleTextOverbar( aKiCadTextItem->GetText() );
2958 aKiCadTextItem->SetText( escapedText );
2959
2960 if( !Assignments.Codedefs.TextCodes.count( aCadstarTextCodeID ) )
2961 return;
2962
2963 TEXTCODE textCode = getTextCode( aCadstarTextCodeID );
2964 int textHeight = KiROUND( (double) getKiCadLength( textCode.Height ) * TXT_HEIGHT_RATIO );
2965 int textWidth = getKiCadLength( textCode.Width );
2966
2967 // The width is zero for all non-cadstar fonts. Using a width equal to 2/3 the height seems
2968 // to work well for most fonts.
2969 if( textWidth == 0 )
2970 textWidth = getKiCadLength( 2LL * textCode.Height / 3LL );
2971
2972 aKiCadTextItem->SetTextWidth( textWidth );
2973 aKiCadTextItem->SetTextHeight( textHeight );
2974
2975#if 0
2976 // EEschema currently supports only normal vs bold for text thickness.
2977 aKiCadTextItem->SetTextThickness( getKiCadLength( textCode.LineWidth ) );
2978#endif
2979
2980 // Must come after SetTextSize()
2981 aKiCadTextItem->SetBold( textCode.Font.Modifier1 == FONT_BOLD );
2982 aKiCadTextItem->SetItalic( textCode.Font.Italic );
2983}
2984
2985
2987 const TEXTCODE_ID& aCadstarTextCodeID,
2988 const ALIGNMENT& aCadstarAlignment,
2989 const JUSTIFICATION& aCadstarJustification,
2990 const long long aCadstarOrientAngle,
2991 bool aMirrored )
2992{
2993 applyTextCodeIfExists( aKiCadTextItem, aCadstarTextCodeID );
2994 aKiCadTextItem->SetTextAngle( getAngle( aCadstarOrientAngle ) );
2995
2996 // Justification ignored for now as not supported in Eeschema, but leaving this code in
2997 // place for future upgrades.
2998 // TODO update this when Eeschema supports justification independent of anchor position.
2999 ALIGNMENT textAlignment = aCadstarAlignment;
3000
3001 // KiCad mirrors the justification and alignment when the symbol is mirrored but CADSTAR
3002 // specifies it post-mirroring. In contrast, if the text item itself is mirrored (not
3003 // supported in KiCad), CADSTAR specifies the alignment and justification pre-mirroring
3004 if( aMirrored )
3005 textAlignment = mirrorX( aCadstarAlignment );
3006
3007 auto setAlignment =
3008 [&]( EDA_TEXT* aText, ALIGNMENT aAlignment )
3009 {
3010 switch( aAlignment )
3011 {
3012 case ALIGNMENT::NO_ALIGNMENT: // Bottom left of the first line
3013 //No exact KiCad equivalent, so lets move the position of the text
3019 break;
3020
3024 break;
3025
3029 break;
3030
3034 break;
3035
3039 break;
3040
3044 break;
3045
3046 case ALIGNMENT::TOPLEFT:
3049 break;
3050
3054 break;
3055
3059 break;
3060 }
3061 };
3062
3063 SPIN_STYLE spin = getSpinStyle( aCadstarOrientAngle, aMirrored );
3064 EDA_ITEM* textEdaItem = dynamic_cast<EDA_ITEM*>( aKiCadTextItem );
3065 wxCHECK( textEdaItem, /* void */ ); // ensure this is a EDA_ITEM
3066
3067 if( textEdaItem->Type() == SCH_FIELD_T )
3068 {
3069 // Spin style not used. All text justifications are permitted. However, only orientations
3070 // of 0 deg or 90 deg are supported
3071 EDA_ANGLE angle = aKiCadTextItem->GetTextAngle();
3072 angle.Normalize();
3073
3074 int quadrant = KiROUND( angle.AsDegrees() / 90.0 );
3075 quadrant %= 4;
3076
3077 switch( quadrant )
3078 {
3079 case 0:
3080 angle = ANGLE_HORIZONTAL;
3081 break;
3082 case 1:
3083 angle = ANGLE_VERTICAL;
3084 break;
3085 case 2:
3086 angle = ANGLE_HORIZONTAL;
3087 textAlignment = rotate180( textAlignment );
3088 break;
3089 case 3:
3090 angle = ANGLE_VERTICAL;
3091 textAlignment = rotate180( textAlignment );
3092 break;
3093 default:
3094 wxFAIL_MSG( "Unknown Quadrant" );
3095 }
3096
3097 aKiCadTextItem->SetTextAngle( angle );
3098 setAlignment( aKiCadTextItem, textAlignment );
3099 }
3100 else if( textEdaItem->Type() == SCH_TEXT_T )
3101 {
3102 // Note spin style in a SCH_TEXT results in a vertical alignment GR_TEXT_V_ALIGN_BOTTOM
3103 // so need to adjust the location of the text element based on Cadstar's original text
3104 // alignment (anchor position).
3105 setAlignment( aKiCadTextItem, textAlignment );
3106 BOX2I bb = textEdaItem->GetBoundingBox();
3107 int off = static_cast<SCH_TEXT*>( aKiCadTextItem )->GetTextOffset();
3108 VECTOR2I pos;
3109
3110 // Change the anchor point of the text item to make it match the same bounding box
3111 // And correct the error introduced by the text offsetting in KiCad
3112 switch( spin )
3113 {
3114 case SPIN_STYLE::BOTTOM: pos = { bb.GetRight() - off, bb.GetTop() }; break;
3115 case SPIN_STYLE::UP: pos = { bb.GetRight() - off, bb.GetBottom() }; break;
3116 case SPIN_STYLE::LEFT: pos = { bb.GetRight() , bb.GetBottom() + off }; break;
3117 case SPIN_STYLE::RIGHT: pos = { bb.GetLeft() , bb.GetBottom() + off }; break;
3118 default: wxFAIL_MSG( "Unexpected Spin Style" ); break;
3119 }
3120
3121 aKiCadTextItem->SetTextPos( pos );
3122
3123 switch( spin )
3124 {
3125 case SPIN_STYLE::RIGHT: // Horiz Normal Orientation
3126 aKiCadTextItem->SetTextAngle( ANGLE_HORIZONTAL );
3127 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
3128 break;
3129
3130 case SPIN_STYLE::UP: // Vert Orientation UP
3131 aKiCadTextItem->SetTextAngle( ANGLE_VERTICAL );
3132 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
3133 break;
3134
3135 case SPIN_STYLE::LEFT: // Horiz Orientation - Right justified
3136 aKiCadTextItem->SetTextAngle( ANGLE_HORIZONTAL );
3137 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
3138 break;
3139
3140 case SPIN_STYLE::BOTTOM: // Vert Orientation BOTTOM
3141 aKiCadTextItem->SetTextAngle( ANGLE_VERTICAL );
3142 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
3143 break;
3144
3145 default:
3146 wxFAIL_MSG( "Unexpected Spin Style" );
3147 break;
3148 }
3149
3150 aKiCadTextItem->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
3151 }
3152 else if( SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( aKiCadTextItem ) )
3153 {
3154 // We don't want to change position of net labels as that would break connectivity
3155 label->SetSpinStyle( spin );
3156 }
3157 else
3158 {
3159 wxFAIL_MSG( "Unexpected item type" );
3160 }
3161}
3162
3163
3165{
3166 SCH_TEXT* kiTxt = new SCH_TEXT();
3167
3168 kiTxt->SetParent( m_schematic ); // set to the schematic for now to avoid asserts
3169 kiTxt->SetPosition( getKiCadPoint( aCadstarTextElement.Position ) );
3170 kiTxt->SetText( aCadstarTextElement.Text );
3171
3172 applyTextSettings( kiTxt, aCadstarTextElement.TextCodeID, aCadstarTextElement.Alignment,
3173 aCadstarTextElement.Justification, aCadstarTextElement.OrientAngle,
3174 aCadstarTextElement.Mirror );
3175
3176 return kiTxt;
3177}
3178
3179
3181 long long aScalingFactorNumerator,
3182 long long aScalingFactorDenominator )
3183{
3184 LIB_SYMBOL* retval = new LIB_SYMBOL( *aSymbol );
3185
3186 if( aScalingFactorNumerator == aScalingFactorDenominator )
3187 return retval; // 1:1 scale, nothing to do
3188
3189 auto scaleLen =
3190 [&]( int aLength ) -> int
3191 {
3192 return( aLength * aScalingFactorNumerator ) / aScalingFactorDenominator;
3193 };
3194
3195 auto scalePt =
3196 [&]( VECTOR2I aCoord ) -> VECTOR2I
3197 {
3198 return VECTOR2I( scaleLen( aCoord.x ), scaleLen( aCoord.y ) );
3199 };
3200
3201 auto scaleSize =
3202 [&]( VECTOR2I aSize ) -> VECTOR2I
3203 {
3204 return VECTOR2I( scaleLen( aSize.x ), scaleLen( aSize.y ) );
3205 };
3206
3207 LIB_ITEMS_CONTAINER& items = retval->GetDrawItems();
3208
3209 for( SCH_ITEM& item : items )
3210 {
3211 switch( item.Type() )
3212 {
3213 case KICAD_T::SCH_SHAPE_T:
3214 {
3215 SCH_SHAPE& shape = static_cast<SCH_SHAPE&>( item );
3216
3217 if( shape.GetShape() == SHAPE_T::ARC )
3218 {
3219 shape.SetPosition( scalePt( shape.GetPosition() ) );
3220 shape.SetStart( scalePt( shape.GetStart() ) );
3221 shape.SetEnd( scalePt( shape.GetEnd() ) );
3222 }
3223 else if( shape.GetShape() == SHAPE_T::POLY )
3224 {
3225 SHAPE_LINE_CHAIN& poly = shape.GetPolyShape().Outline( 0 );
3226
3227 for( size_t ii = 0; ii < poly.GetPointCount(); ++ii )
3228 poly.SetPoint( ii, scalePt( poly.CPoint( ii ) ) );
3229 }
3230 break;
3231 }
3232
3233 case KICAD_T::SCH_PIN_T:
3234 {
3235 SCH_PIN& pin = static_cast<SCH_PIN&>( item );
3236
3237 pin.SetPosition( scalePt( pin.GetPosition() ) );
3238 pin.SetLength( scaleLen( pin.GetLength() ) );
3239 break;
3240 }
3241
3242 case KICAD_T::SCH_TEXT_T:
3243 {
3244 SCH_TEXT& txt = static_cast<SCH_TEXT&>( item );
3245
3246 txt.SetPosition( scalePt( txt.GetPosition() ) );
3247 txt.SetTextSize( scaleSize( txt.GetTextSize() ) );
3248 break;
3249 }
3250
3251 default:
3252 break;
3253 }
3254 }
3255
3256 return retval;
3257}
3258
3259
3260void CADSTAR_SCH_ARCHIVE_LOADER::fixUpLibraryPins( LIB_SYMBOL* aSymbolToFix, int aGateNumber )
3261{
3262 auto compLambda =
3263 []( const VECTOR2I& aA, const VECTOR2I& aB )
3264 {
3265 return LexicographicalCompare( aA, aB ) < 0;
3266 };
3267
3268 // Store a list of vertical or horizontal segments in the symbol
3269 // Note: Need the custom comparison function to ensure the map is sorted correctly
3270 std::map<VECTOR2I, SHAPE_LINE_CHAIN, decltype( compLambda )> uniqueSegments( compLambda );
3271
3272 LIB_ITEMS_CONTAINER::ITERATOR shapeIt = aSymbolToFix->GetDrawItems().begin( SCH_SHAPE_T );
3273
3274 for( ; shapeIt != aSymbolToFix->GetDrawItems().end( SCH_SHAPE_T ); ++shapeIt )
3275 {
3276 SCH_SHAPE& shape = static_cast<SCH_SHAPE&>( *shapeIt );
3277
3278 if( aGateNumber > 0 && shape.GetUnit() != aGateNumber )
3279 continue;
3280
3281 if( shape.GetShape() != SHAPE_T::POLY )
3282 continue;
3283
3284 SHAPE_LINE_CHAIN poly = shape.GetPolyShape().Outline( 0 );
3285
3286 if( poly.GetPointCount() == 2 )
3287 {
3288 VECTOR2I pt0 = poly.CPoint( 0 );
3289 VECTOR2I pt1 = poly.CPoint( 1 );
3290
3291 if( pt0 != pt1 && uniqueSegments.count( pt0 ) == 0 && uniqueSegments.count( pt1 ) == 0 )
3292 {
3293 // we are only interested in vertical or horizontal segments
3294 if( pt0.x == pt1.x || pt0.y == pt1.y )
3295 {
3296 uniqueSegments.insert( { pt0, poly } );
3297 uniqueSegments.insert( { pt1, poly } );
3298 }
3299 }
3300 }
3301 }
3302
3303 for( SCH_PIN* pin : aSymbolToFix->GetPins( aGateNumber, 0 ) )
3304 {
3305 auto setPinOrientation =
3306 [&]( const EDA_ANGLE& aAngle )
3307 {
3308 EDA_ANGLE angle( aAngle );
3309 angle.Normalize180();
3310
3311 if( angle >= -ANGLE_45 && angle <= ANGLE_45 )
3312 pin->SetOrientation( PIN_ORIENTATION::PIN_RIGHT ); // 0 degrees
3313 else if( angle >= ANGLE_45 && angle <= ANGLE_135 )
3314 pin->SetOrientation( PIN_ORIENTATION::PIN_UP ); // 90 degrees
3315 else if( angle >= ANGLE_135 || angle <= -ANGLE_135 )
3316 pin->SetOrientation( PIN_ORIENTATION::PIN_LEFT ); // 180 degrees
3317 else
3318 pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN ); // -90 degrees
3319 };
3320
3321 if( uniqueSegments.count( pin->GetPosition() ) )
3322 {
3323 SHAPE_LINE_CHAIN& poly = uniqueSegments.at( pin->GetPosition() );
3324
3325 VECTOR2I otherPt = poly.CPoint( 0 );
3326
3327 if( otherPt == pin->GetPosition() )
3328 otherPt = poly.CPoint( 1 );
3329
3330 VECTOR2I vec( otherPt - pin->GetPosition() );
3331
3332 pin->SetLength( vec.EuclideanNorm() );
3333 setPinOrientation( EDA_ANGLE( vec ) );
3334 }
3335 }
3336}
3337
3338
3339std::pair<VECTOR2I, VECTOR2I>
3341{
3342 VECTOR2I upperLeft( Assignments.Settings.DesignLimit.x, 0 );
3343 VECTOR2I lowerRight( 0, Assignments.Settings.DesignLimit.y );
3344
3345 for( const VERTEX& v : aCadstarFigure.Shape.Vertices )
3346 {
3347 if( upperLeft.x > v.End.x )
3348 upperLeft.x = v.End.x;
3349
3350 if( upperLeft.y < v.End.y )
3351 upperLeft.y = v.End.y;
3352
3353 if( lowerRight.x < v.End.x )
3354 lowerRight.x = v.End.x;
3355
3356 if( lowerRight.y > v.End.y )
3357 lowerRight.y = v.End.y;
3358 }
3359
3360 for( CUTOUT cutout : aCadstarFigure.Shape.Cutouts )
3361 {
3362 for( const VERTEX& v : aCadstarFigure.Shape.Vertices )
3363 {
3364 if( upperLeft.x > v.End.x )
3365 upperLeft.x = v.End.x;
3366
3367 if( upperLeft.y < v.End.y )
3368 upperLeft.y = v.End.y;
3369
3370 if( lowerRight.x < v.End.x )
3371 lowerRight.x = v.End.x;
3372
3373 if( lowerRight.y > v.End.y )
3374 lowerRight.y = v.End.y;
3375 }
3376 }
3377
3378 VECTOR2I upperLeftKiCad = getKiCadPoint( upperLeft );
3379 VECTOR2I lowerRightKiCad = getKiCadPoint( lowerRight );
3380
3381 VECTOR2I size = lowerRightKiCad - upperLeftKiCad;
3382
3383 return { upperLeftKiCad, VECTOR2I( abs( size.x ), abs( size.y ) ) };
3384}
3385
3386
3388{
3389 VECTOR2I retval;
3390
3391 retval.x = getKiCadLength( aCadstarPoint.x - m_designCenter.x );
3392 retval.y = -getKiCadLength( aCadstarPoint.y - m_designCenter.y );
3393
3394 return retval;
3395}
3396
3397
3399 const VECTOR2I& aCadstarCentre )
3400{
3401 VECTOR2I retval;
3402
3403 retval.x = getKiCadLength( aCadstarPoint.x - aCadstarCentre.x );
3404 retval.y = -getKiCadLength( aCadstarPoint.y - aCadstarCentre.y );
3405
3406 return retval;
3407}
3408
3409
3411 const VECTOR2I& aMoveVector,
3412 const EDA_ANGLE& aRotation,
3413 const double& aScalingFactor,
3414 const VECTOR2I& aTransformCentre,
3415 const bool& aMirrorInvert )
3416{
3417 VECTOR2I retVal = aPoint;
3418
3419 if( aScalingFactor != 1.0 )
3420 {
3421 //scale point
3422 retVal -= aTransformCentre;
3423 retVal.x = KiROUND( retVal.x * aScalingFactor );
3424 retVal.y = KiROUND( retVal.y * aScalingFactor );
3425 retVal += aTransformCentre;
3426 }
3427
3428 if( aMirrorInvert )
3429 MIRROR( retVal.x, aTransformCentre.x );
3430
3431 if( !aRotation.IsZero() )
3432 RotatePoint( retVal, aTransformCentre, aRotation );
3433
3434 if( aMoveVector != VECTOR2I{ 0, 0 } )
3435 retVal += aMoveVector;
3436
3437 return retVal;
3438}
3439
3440
3442{
3443 return sqrt( ( (double) aPoint.x * (double) aPoint.x )
3444 + ( (double) aPoint.y * (double) aPoint.y ) );
3445}
const char * name
Definition: DXF_plotter.cpp:62
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:114
constexpr double SCH_IU_PER_MM
Schematic internal units 1=100nm.
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)
Correct 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 canceled.
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:229
double AsDegrees() const
Definition: eda_angle.h:116
bool IsZero() const
Definition: eda_angle.h:136
EDA_ANGLE Normalize180()
Definition: eda_angle.h:268
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:98
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:110
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:110
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:113
EDA_ITEM * GetParent() const
Definition: eda_item.h:112
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:337
SHAPE_T GetShape() const
Definition: eda_shape.h:168
void SetPolyShape(const SHAPE_POLY_SET &aShape)
Definition: eda_shape.h:345
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:215
void SetStart(const VECTOR2I &aStart)
Definition: eda_shape.h:177
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:173
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:219
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Set the three controlling points for an arc.
Definition: eda_shape.cpp:1041
void SetFillMode(FILL_T aFill)
Definition: eda_shape.cpp:540
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:264
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:144
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition: eda_text.cpp:533
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:97
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:578
int GetTextWidth() const
Definition: eda_text.h:261
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition: eda_text.cpp:417
void SetTextWidth(int aWidth)
Definition: eda_text.cpp:556
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:386
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.cpp:284
void SetTextHeight(int aHeight)
Definition: eda_text.cpp:567
void SetBold(bool aBold)
Set the text to be bold - this will also update the font if needed.
Definition: eda_text.cpp:335
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:270
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition: eda_text.cpp:299
int GetTextThickness() const
Definition: eda_text.h:125
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition: eda_text.cpp:307
void SetMultilineAllowed(bool aAllow)
Definition: eda_text.cpp:401
VECTOR2I GetTextSize() const
Definition: eda_text.h:258
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition: eda_text.cpp:409
iterator end()
Return a read/write iterator that points to one past the last element in the EE_RTREE.
Definition: sch_rtree.h:289
iterator begin()
Return a read/write iterator that points to the first.
Definition: sch_rtree.h:281
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:111
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition: lib_id.cpp:100
UTF8 Format() const
Definition: lib_id.cpp:119
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
Definition: lib_id.cpp:192
Define a library symbol object.
Definition: lib_symbol.h:85
void SetGlobalPower()
Definition: lib_symbol.cpp:475
std::vector< SCH_PIN * > GetPins(int aUnit, int aBodyStyle) const
Return a list of pin object pointers from the draw item list.
Definition: lib_symbol.cpp:799
void SetUnitCount(int aCount, bool aDuplicateDrawItems=true)
Set the units per symbol count.
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition: lib_symbol.h:519
wxString GetName() const override
Definition: lib_symbol.h:149
SCH_FIELD & GetValueField()
Return reference to the value field.
Definition: lib_symbol.h:334
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:785
virtual void SetName(const wxString &aName)
Definition: lib_symbol.cpp:328
SCH_FIELD & GetReferenceField()
Return reference to the reference designator field.
Definition: lib_symbol.h:338
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:262
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:248
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:65
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:149
virtual std::map< wxString, wxString > & GetTextVars() const
Definition: project.cpp:98
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition: reporter.h:102
Holds all the data relating to one schematic.
Definition: schematic.h:88
PROJECT & Project() const
Return a reference to the project this schematic is part of.
Definition: schematic.h:103
void SetSize(const VECTOR2I &aSize)
Definition: sch_bus_entry.h:74
Class for a wire to bus entry.
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
Definition: sch_field.cpp:1103
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_field.cpp:1317
void SetText(const wxString &aText) override
Definition: sch_field.cpp:1089
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
Definition: sch_label.cpp:1950
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
Definition: sch_label.cpp:2131
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:168
SCH_ITEM * Duplicate(bool addToParentGroup, SCH_COMMIT *aCommit=nullptr, bool doClone=false) const
Routine to create a new copy of given item.
Definition: sch_item.cpp:137
int GetUnit() const
Definition: sch_item.h:239
void SetLayer(SCH_LAYER_ID aLayer)
Definition: sch_item.h:314
virtual void SetUnit(int aUnit)
Definition: sch_item.h:238
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_junction.h:108
void SetShape(LABEL_FLAG_SHAPE aShape)
Definition: sch_label.h:177
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_label.cpp:390
void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo) override
Definition: sch_label.cpp:580
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
Definition: sch_label.cpp:316
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:42
void SetStartPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:140
void SetLineWidth(const int aSize)
Definition: sch_line.cpp:315
VECTOR2I GetEndPoint() const
Definition: sch_line.h:144
VECTOR2I GetStartPoint() const
Definition: sch_line.h:139
void SetLineStyle(const LINE_STYLE aStyle)
Definition: sch_line.cpp:286
void SetEndPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:145
void SetNumber(const wxString &aNumber)
Definition: sch_pin.cpp:541
const PAGE_INFO & GetPageSettings() const
Definition: sch_screen.h:139
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Definition: sch_screen.cpp:160
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:140
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition: sch_screen.h:117
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
Definition: sch_screen.cpp:123
void Update(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Update aItem's bounding box in the tree.
Definition: sch_screen.cpp:323
void SetPosition(const VECTOR2I &aPos) override
Definition: sch_shape.h:85
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: sch_shape.cpp:61
void AddPoint(const VECTOR2I &aPosition)
Definition: sch_shape.cpp:400
VECTOR2I GetPosition() const override
Definition: sch_shape.h:84
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:47
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition: sch_sheet.h:321
void AddPin(SCH_SHEET_PIN *aSheetPin)
Add aSheetPin to the sheet.
Definition: sch_sheet.cpp:398
std::vector< SCH_FIELD > & GetFields()
Return a reference to the vector holding the sheet's fields.
Definition: sch_sheet.h:87
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this sheet.
Definition: sch_sheet.cpp:367
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:787
VECTOR2I GetSize() const
Definition: sch_sheet.h:118
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:116
VECTOR2I GetPosition() const override
Definition: sch_sheet.h:415
void SetFields(const std::vector< SCH_FIELD > &aFields)
Set multiple schematic fields.
Definition: sch_sheet.cpp:389
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Definition: sch_sheet.cpp:137
static bool ClassOf(const EDA_ITEM *aItem)
Definition: sch_sheet.h:63
void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo) override
Definition: sch_sheet.cpp:635
Schematic symbol object.
Definition: sch_symbol.h:75
BOX2I GetBodyAndPinsBoundingBox() const override
Return a bounding box for the symbol body and pins but not the fields.
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_symbol.h:768
void UpdatePins()
Updates the cache of SCH_PIN objects for each pin.
Definition: sch_symbol.cpp:288
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:600
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
Definition: sch_symbol.cpp:788
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.
Definition: sch_symbol.cpp:815
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition: sch_symbol.h:183
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition: sch_symbol.cpp:760
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:297
const VECTOR2I & GetArcMid() const
Definition: shape_arc.h:118
const VECTOR2I & GetP1() const
Definition: shape_arc.h:117
const VECTOR2I & GetP0() const
Definition: shape_arc.h:116
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:125
SPIN_STYLE MirrorY()
Mirror the label spin style across the Y axis or simply swaps left and right.
Definition: sch_label.cpp:141
SPIN_STYLE RotateCCW()
Definition: sch_label.cpp:109
Simple container to manage line stroke parameters.
Definition: stroke_params.h:94
virtual void SetShowPinNumbers(bool aShow)
Set or clear the pin number visibility flag.
Definition: symbol.h:164
virtual void SetShowPinNames(bool aShow)
Set or clear the pin name visibility flag.
Definition: symbol.h:158
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:411
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:413
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition: eda_angle.h:408
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition: eda_angle.h:407
static constexpr EDA_ANGLE ANGLE_45
Definition: eda_angle.h:412
static constexpr EDA_ANGLE ANGLE_270
Definition: eda_angle.h:416
static constexpr EDA_ANGLE ANGLE_180
Definition: eda_angle.h:415
static constexpr EDA_ANGLE ANGLE_135
Definition: eda_angle.h:414
#define IGNORE_PARENT_GROUP
Definition: eda_item.h:55
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:439
@ LAYER_DEVICE
Definition: layer_ids.h:456
@ LAYER_WIRE
Definition: layer_ids.h:442
@ LAYER_NOTES
Definition: layer_ids.h:457
@ LAYER_BUS
Definition: layer_ids.h:443
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
@ AUTOPLACE_AUTO
Definition: sch_item.h:71
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:63
#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
Represent a cutout in a closed shape (e.g.
long ScaleRatioNumerator
Documentation symbols can be arbitrarily scaled when added to a design.
long ScaleRatioDenominator
Documentation symbols can be arbitrarily scaled when added to a design.
POINT Origin
Origin of the component (this is used as the reference point when placing the component in the design...
LAYER_ID LayerID
Move all objects in the Symdef to this layer.
SYMDEF_ID SymdefID
Normally documentation symbols only have TEXT, FIGURE and TEXT_LOCATION objects which are all drawn o...
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.
Represent a point in x,y coordinates.
SHAPE_POLY_SET ConvertToPolySet(const std::function< VECTOR2I(const VECTOR2I &)> aCadstarToKicadPointCallback, int 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.
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:103
const double IU_PER_MILS
Definition: base_units.h:77
constexpr int MilsToIU(int mils) const
Definition: base_units.h:97
bool cw
VECTOR2I end
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:173
@ SCH_FIELD_T
Definition: typeinfo.h:151
@ SCH_SHAPE_T
Definition: typeinfo.h:150
@ SCH_SHEET_PIN_T
Definition: typeinfo.h:175
@ SCH_TEXT_T
Definition: typeinfo.h:152
constexpr int sign(T val)
Definition: util.h:145
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695
constexpr int LexicographicalCompare(const VECTOR2< T > &aA, const VECTOR2< T > &aB)
Definition: vector2d.h:644
Definition of file extensions used in Kicad.