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