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