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