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 m_reporter->Report( wxString::Format( _( "The CADSTAR design contains variants which has "
388 "no KiCad equivalent. Only the master variant "
389 "('%s') was loaded." ),
390 Schematic.VariantHierarchy.Variants.at( "V0" ).Name ),
392 }
393
394 if( Schematic.Groups.size() > 0 )
395 {
396 m_reporter->Report( _( "The CADSTAR design contains grouped items which has no KiCad "
397 "equivalent. Any grouped items have been ungrouped." ),
399 }
400
401 if( Schematic.ReuseBlocks.size() > 0 )
402 {
403 m_reporter->Report( _( "The CADSTAR design contains re-use blocks which has no KiCad "
404 "equivalent. The re-use block information has been discarded during "
405 "the import." ),
407 }
408
409
410 // For all sheets, center all elements and re calculate the page size:
411 for( std::pair<LAYER_ID, SCH_SHEET*> sheetPair : m_sheetMap )
412 {
413 SCH_SHEET* sheet = sheetPair.second;
414
415 // Calculate the new sheet size.
416 BOX2I sheetBoundingBox;
417
418 for( SCH_ITEM* item : sheet->GetScreen()->Items() )
419 {
420 BOX2I bbox;
421
422 // Only use the visible fields of the symbols to calculate their bounding box
423 // (hidden fields could be very long and artificially enlarge the sheet bounding box)
424 if( item->Type() == SCH_SYMBOL_T )
425 {
426 SCH_SYMBOL* comp = static_cast<SCH_SYMBOL*>( item );
427 bbox = comp->GetBodyAndPinsBoundingBox();
428
429 for( const SCH_FIELD& field : comp->GetFields() )
430 {
431 if( field.IsVisible() )
432 bbox.Merge( field.GetBoundingBox() );
433 }
434 }
435 else if( item->Type() == SCH_TEXT_T )
436 {
437 SCH_TEXT* txtItem = static_cast<SCH_TEXT*>( item );
438 wxString txt = txtItem->GetText();
439
440 if( txt.Contains( "${" ) )
441 continue; // We can't calculate bounding box of text items with variables
442 else
443 bbox = txtItem->GetBoundingBox();
444 }
445 else
446 {
447 bbox = item->GetBoundingBox();
448 }
449
450 sheetBoundingBox.Merge( bbox );
451 }
452
453 // Find the screen grid of the original CADSTAR design
454 int grid = Assignments.Grids.ScreenGrid.Param1;
455
456 if( Assignments.Grids.ScreenGrid.Type == GRID_TYPE::FRACTIONALGRID )
457 grid = grid / Assignments.Grids.ScreenGrid.Param2;
458 else if( Assignments.Grids.ScreenGrid.Param2 > grid )
459 grid = Assignments.Grids.ScreenGrid.Param2;
460
462
463 auto roundToNearestGrid =
464 [&]( int aNumber ) -> int
465 {
466 int error = aNumber % grid;
467 int absError = sign( error ) * error;
468
469 if( absError > ( grid / 2 ) )
470 return aNumber + ( sign( error ) * grid ) - error;
471 else
472 return aNumber - error;
473 };
474
475 // When exporting to pdf, CADSTAR applies a margin of 3percent of the longest dimension (height
476 // or width) to all 4 sides (top, bottom, left right). For the import, we are also rounding
477 // the margin to the nearest grid, ensuring all items remain on the grid.
478 VECTOR2I targetSheetSize = sheetBoundingBox.GetSize();
479 int longestSide = std::max( targetSheetSize.x, targetSheetSize.y );
480 int margin = ( (double) longestSide * 0.03 );
481 margin = roundToNearestGrid( margin );
482 targetSheetSize += margin * 2;
483
484 // Update page size always
485 PAGE_INFO pageInfo = sheet->GetScreen()->GetPageSettings();
486 pageInfo.SetWidthMils( schIUScale.IUToMils( targetSheetSize.x ) );
487 pageInfo.SetHeightMils( schIUScale.IUToMils( targetSheetSize.y ) );
488
489 // Set the new sheet size.
490 sheet->GetScreen()->SetPageSettings( pageInfo );
491
492 VECTOR2I pageSizeIU = sheet->GetScreen()->GetPageSettings().GetSizeIU( schIUScale.IU_PER_MILS );
493 VECTOR2I sheetcentre( pageSizeIU.x / 2, pageSizeIU.y / 2 );
494 VECTOR2I itemsCentre = sheetBoundingBox.Centre();
495
496 // round the translation to nearest point on the grid
497 VECTOR2I translation = sheetcentre - itemsCentre;
498 translation.x = roundToNearestGrid( translation.x );
499 translation.y = roundToNearestGrid( translation.y );
500
501 // Translate the items.
502 std::vector<SCH_ITEM*> allItems;
503
504 std::copy( sheet->GetScreen()->Items().begin(), sheet->GetScreen()->Items().end(),
505 std::back_inserter( allItems ) );
506
507 for( SCH_ITEM* item : allItems )
508 {
509 item->Move( translation );
510 item->ClearFlags();
511 sheet->GetScreen()->Update( item );
512 }
513 }
514
515 checkPoint();
516
517 m_reporter->Report( _( "CADSTAR fonts are different to the ones in KiCad. This will likely "
518 "result in alignment issues. Please review the imported text elements "
519 "carefully and correct manually if required." ),
521
522 m_reporter->Report( _( "The CADSTAR design has been imported successfully.\n"
523 "Please review the import errors and warnings (if any)." ) );
524}
525
526
528{
529 LONGPOINT designLimit = Assignments.Settings.DesignLimit;
530
531 //Note: can't use getKiCadPoint() due VECTOR2I being int - need long long to make the check
532 long long designSizeXkicad = (long long) designLimit.x / KiCadUnitDivider;
533 long long designSizeYkicad = (long long) designLimit.y / KiCadUnitDivider;
534
535 // Max size limited by the positive dimension of VECTOR2I (which is an int)
536 constexpr long long maxDesignSizekicad = std::numeric_limits<int>::max();
537
538 if( designSizeXkicad > maxDesignSizekicad || designSizeYkicad > maxDesignSizekicad )
539 {
540 THROW_IO_ERRORF( _( "The design is too large and cannot be imported into KiCad. \n"
541 "Please reduce the maximum design size in CADSTAR by navigating to: \n"
542 "Design Tab -> Properties -> Design Options -> Maximum Design Size. \n"
543 "Current Design size: %.2f, %.2f millimeters. \n" //format:allow
544 "Maximum permitted design size: %.2f, %.2f millimeters.\n" ), //format:allow
545 (double) designSizeXkicad / SCH_IU_PER_MM,
546 (double) designSizeYkicad / SCH_IU_PER_MM,
547 (double) maxDesignSizekicad / SCH_IU_PER_MM,
548 (double) maxDesignSizekicad / SCH_IU_PER_MM );
549 }
550}
551
552
554{
555 const std::vector<LAYER_ID>& orphanSheets = findOrphanSheets();
556 SCH_SHEET_PATH rootPath;
557 rootPath.push_back( m_rootSheet );
558 rootPath.SetPageNumber( wxT( "1" ) );
559
560 if( orphanSheets.size() > 1 )
561 {
562 int x = 1;
563 int y = 1;
564
565 for( LAYER_ID sheetID : orphanSheets )
566 {
567 VECTOR2I pos( x * schIUScale.MilsToIU( 1000 ), y * schIUScale.MilsToIU( 1000 ) );
568 VECTOR2I siz( schIUScale.MilsToIU( 1000 ), schIUScale.MilsToIU( 1000 ) );
569
570 loadSheetAndChildSheets( sheetID, pos, siz, rootPath );
571
572 x += 2;
573
574 if( x > 10 ) // start next row
575 {
576 x = 1;
577 y += 2;
578 }
579 }
580 }
581 else if( orphanSheets.size() > 0 )
582 {
583 LAYER_ID rootSheetID = orphanSheets.at( 0 );
584
585 wxFileName loadedFilePath = wxFileName( Filename );
586
587 std::string filename = wxString::Format( "%s_%02d", loadedFilePath.GetName(),
588 getSheetNumber( rootSheetID ) )
589 .ToStdString();
590 ReplaceIllegalFileNameChars( filename );
591 filename += wxT( "." ) + wxString( FILEEXT::KiCadSchematicFileExtension );
592
593 wxFileName fn( m_schematic->Project().GetProjectPath() + filename );
594 m_rootSheet->GetScreen()->SetFileName( fn.GetFullPath() );
595
596 m_sheetMap.insert( { rootSheetID, m_rootSheet } );
597 loadChildSheets( rootSheetID, rootPath );
598 }
599 else if( Header.Format.Type == "SYMBOL" )
600 {
601 THROW_IO_ERROR( _( "The selected file is a CADSTAR symbol library. It does not contain a "
602 "schematic design so cannot be imported/opened in this way." ) );
603 }
604 else
605 {
606 THROW_IO_ERROR( _( "The CADSTAR schematic might be corrupt: there is no root sheet." ) );
607 }
608}
609
610
612{
613 for( std::pair<BLOCK_ID, BLOCK> blockPair : Schematic.Blocks )
614 {
615 BLOCK& block = blockPair.second;
616 LAYER_ID sheetID = "";
617
618 if( block.Type == BLOCK::TYPE::PARENT )
619 sheetID = block.LayerID;
620 else if( block.Type == BLOCK::TYPE::CHILD )
621 sheetID = block.AssocLayerID;
622 else
623 continue;
624
625 if( m_sheetMap.find( sheetID ) != m_sheetMap.end() )
626 {
627 SCH_SHEET* sheet = m_sheetMap.at( sheetID );
628
629 for( std::pair<TERMINAL_ID, TERMINAL> termPair : block.Terminals )
630 {
631 TERMINAL term = termPair.second;
632 wxString name = "YOU SHOULDN'T SEE THIS TEXT. THIS IS A BUG.";
633
634 SCH_HIERLABEL* sheetPin = nullptr;
635
636 if( block.Type == BLOCK::TYPE::PARENT )
637 sheetPin = new SCH_HIERLABEL();
638 else if( block.Type == BLOCK::TYPE::CHILD )
639 sheetPin = new SCH_SHEET_PIN( sheet );
640
641 sheetPin->SetText( name );
643 sheetPin->SetSpinStyle( getSpinStyle( term.OrientAngle, false ) );
644 sheetPin->SetPosition( getKiCadPoint( term.Position ) );
645
646 if( sheetPin->Type() == SCH_SHEET_PIN_T )
647 sheet->AddPin( (SCH_SHEET_PIN*) sheetPin );
648 else
649 sheet->GetScreen()->Append( sheetPin );
650
651 BLOCK_PIN_ID blockPinID = std::make_pair( block.ID, term.ID );
652 m_sheetPinMap.insert( { blockPinID, sheetPin } );
653 }
654 }
655 }
656}
657
658
660{
661 for( std::pair<PART_ID, PART> partPair : Parts.PartDefinitions )
662 {
663 PART_ID partID = partPair.first;
664 PART part = partPair.second;
665
666 wxString escapedPartName = EscapeString( part.Name, CTX_LIBID );
667 std::unique_ptr<LIB_SYMBOL> kiSym = std::make_unique<LIB_SYMBOL>( escapedPartName );
668
669 kiSym->SetUnitCount( part.Definition.GateSymbols.size(), true );
670 bool ok = true;
671
672 for( std::pair<GATE_ID, PART::DEFINITION::GATE> gatePair : part.Definition.GateSymbols )
673 {
674 GATE_ID gateID = gatePair.first;
675 PART::DEFINITION::GATE gate = gatePair.second;
676 SYMDEF_ID symbolID = getSymDefFromName( gate.Name, gate.Alternate );
677
678 if( symbolID.IsEmpty() )
679 {
680 m_reporter->Report( wxString::Format( _( "Part definition '%s' references symbol "
681 "'%s' (alternate '%s') which could not be "
682 "found in the symbol library. The part has "
683 "not been loaded into the KiCad library." ),
684 part.Name,
685 gate.Name,
686 gate.Alternate ),
688
689 ok = false;
690 break;
691 }
692
693 m_partSymbolsMap.insert( { { partID, gateID }, symbolID } );
694 loadSymbolGateAndPartFields( symbolID, part, gateID, kiSym.get() );
695 }
696
697 bool saveInLibrary = ok && part.Definition.GateSymbols.size() != 0;
698
699 if( !saveInLibrary )
700 {
701 if( part.Definition.GateSymbols.size() == 0 )
702 {
703 m_reporter->Report( wxString::Format( _( "Part definition '%s' has an incomplete "
704 "definition (no symbol definitions are "
705 "associated with it). The part has not "
706 "been loaded into the KiCad library." ),
707 part.Name ),
709 }
710
711 // Don't save in the library, but still keep it cached as some of the units might have
712 // been loaded correctly (saving us time later on), plus the part definition contains
713 // the part name, which is important to load
714 }
715
716 // The loader owns the symbol for the rest of the load; the maps below only hold aliases
717 LIB_SYMBOL* symbol = kiSym.get();
718 m_ownedSymbols.push_back( std::move( kiSym ) );
719
720 bool inserted = m_partMap.insert( { partID, symbol } ).second;
721 wxCHECK2( inserted, continue );
722
723 if( saveInLibrary )
724 m_loadedSymbols.push_back( symbol );
725
726 checkPoint();
727 }
728}
729
730
732{
733 for( std::pair<SYMBOL_ID, SYMBOL> symPair : Schematic.Symbols )
734 {
735 SYMBOL sym = symPair.second;
736
737 if( !sym.VariantID.empty() && sym.VariantParentSymbolID != sym.ID )
738 continue; // Only load master Variant
739
740 if( sym.IsComponent )
741 {
742 if( m_partMap.find( sym.PartRef.RefID ) == m_partMap.end() )
743 {
744 m_reporter->Report( wxString::Format( _( "Symbol '%s' references part '%s' which could not be "
745 "found in the library. The symbol was not loaded." ),
747 sym.PartRef.RefID ),
749
750 continue;
751 }
752
753 if( sym.GateID.IsEmpty() )
754 sym.GateID = wxT( "A" ); // Assume Gate "A" if unspecified
755
756 PART_GATE_ID partSymbolID = { sym.PartRef.RefID, sym.GateID };
757 LIB_SYMBOL* kiSym = m_partMap.at( sym.PartRef.RefID );
758 std::unique_ptr<LIB_SYMBOL> kiSymCopy;
759
760 // The symbol definition in the part either does not exist for this gate number
761 // or is different to the symbol instance. We need to reload the gate for this
762 // symbol
763 if( m_partSymbolsMap.find( partSymbolID ) == m_partSymbolsMap.end()
764 || m_partSymbolsMap.at( partSymbolID ) != sym.SymdefID )
765 {
766 kiSymCopy = std::make_unique<LIB_SYMBOL>( *kiSym );
767 kiSym = kiSymCopy.get();
768 const PART& part = Parts.PartDefinitions.at( sym.PartRef.RefID );
769 loadSymbolGateAndPartFields( sym.SymdefID, part, sym.GateID, kiSym );
770 }
771
772 std::unique_ptr<LIB_SYMBOL> scaledPart(
774
775 EDA_ANGLE symOrient = ANGLE_0;
776 SCH_SYMBOL* symbol = loadSchematicSymbol( sym, *scaledPart, symOrient );
777
778 SCH_FIELD* refField = symbol->GetField( FIELD_T::REFERENCE );
779
780 sym.ComponentRef.Designator.Replace( wxT( "\n" ), wxT( "\\n" ) );
781 sym.ComponentRef.Designator.Replace( wxT( "\r" ), wxT( "\\r" ) );
782 sym.ComponentRef.Designator.Replace( wxT( "\t" ), wxT( "\\t" ) );
783 sym.ComponentRef.Designator.Replace( wxT( " " ), wxT( "_" ) );
784
785 refField->SetText( sym.ComponentRef.Designator );
786 loadSymbolFieldAttribute( sym.ComponentRef.AttrLoc, symOrient, sym.Mirror, refField );
787
788 if( sym.HasPartRef )
789 {
790 SCH_FIELD* partField = symbol->GetField( PartNameFieldName );
791
792 if( !partField )
793 partField = symbol->AddField( SCH_FIELD( symbol, FIELD_T::USER, PartNameFieldName ) );
794
795 wxASSERT( partField->GetName() == PartNameFieldName );
796
797 wxString partname = getPart( sym.PartRef.RefID ).Name;
798 partname.Replace( wxT( "\n" ), wxT( "\\n" ) );
799 partname.Replace( wxT( "\r" ), wxT( "\\r" ) );
800 partname.Replace( wxT( "\t" ), wxT( "\\t" ) );
801 partField->SetText( partname );
802
803 loadSymbolFieldAttribute( sym.PartRef.AttrLoc, symOrient, sym.Mirror, partField );
804
805 partField->SetVisible( SymbolPartNameColor.IsVisible );
806 }
807
808 for( auto& attr : sym.AttributeValues )
809 {
810 ATTRIBUTE_VALUE attrVal = attr.second;
811
812 if( attrVal.HasLocation )
813 {
814 wxString attrName = getAttributeName( attrVal.AttributeID );
815 SCH_FIELD* attrField = symbol->GetField( attrName );
816
817 if( !attrField )
818 attrField = symbol->AddField( SCH_FIELD( symbol, FIELD_T::USER, attrName ) );
819
820 wxASSERT( attrField->GetName() == attrName );
821
822 attrVal.Value.Replace( wxT( "\n" ), wxT( "\\n" ) );
823 attrVal.Value.Replace( wxT( "\r" ), wxT( "\\r" ) );
824 attrVal.Value.Replace( wxT( "\t" ), wxT( "\\t" ) );
825 attrField->SetText( attrVal.Value );
826
827 loadSymbolFieldAttribute( attrVal.AttributeLocation, symOrient, sym.Mirror,
828 attrField );
829 attrField->SetVisible( isAttributeVisible( attrVal.AttributeID ) );
830 }
831 }
832 }
833 else if( sym.IsSymbolVariant )
834 {
835 if( Library.SymbolDefinitions.find( sym.SymdefID ) == Library.SymbolDefinitions.end() )
836 {
837 THROW_IO_ERRORF( _( "Symbol ID '%s' references library symbol '%s' which could not be found "
838 "in the library. Did you export all items of the design?" ),
839 sym.ID,
840 sym.PartRef.RefID );
841 }
842
843 SYMDEF_SCM libSymDef = Library.SymbolDefinitions.at( sym.SymdefID );
844
845 if( libSymDef.Terminals.size() != 1 )
846 {
847 THROW_IO_ERRORF( _( "Symbol ID '%s' is a signal reference or global signal but it has too "
848 "many pins. The expected number of pins is 1 but %d were found." ),
849 sym.ID,
850 libSymDef.Terminals.size() );
851 }
852
853 if( sym.SymbolVariant.Type == SYMBOLVARIANT::TYPE::GLOBALSIGNAL )
854 {
855 SYMDEF_ID symID = sym.SymdefID;
856 LIB_SYMBOL* kiPart = nullptr;
857
858 // In CADSTAR "GlobalSignal" is a special type of symbol which defines
859 // a Power Symbol. The "Alternate" name defines the default net name of
860 // the power symbol but this can be overridden in the design itself.
861 wxString libraryNetName = Library.SymbolDefinitions.at( symID ).Alternate;
862
863 // Name of the net that the symbol instance in CADSTAR refers to:
864 wxString symbolInstanceNetName = sym.SymbolVariant.Reference;
865 symbolInstanceNetName = EscapeString( symbolInstanceNetName, CTX_LIBID );
866
867 // Name of the symbol we will use for saving the part in KiCad
868 // Note: In CADSTAR all power symbols will start have the reference name be
869 // "GLOBALSIGNAL" followed by the default net name, so it makes sense to save
870 // the symbol in KiCad as the default net name as well.
871 wxString libPartName = libraryNetName;
872
873 // In CADSTAR power symbol instances can refer to a different net to that defined
874 // in the library. This causes problems in KiCad v6 as it breaks connectivity when
875 // the user decides to update all symbols from library. We handle this by creating
876 // individual versions of the power symbol for each net name.
877 if( libPartName != symbolInstanceNetName )
878 {
879 libPartName += wxT( " (" ) + symbolInstanceNetName + wxT( ")" );
880 }
881
882 if( m_powerSymLibMap.find( libPartName ) == m_powerSymLibMap.end() )
883 {
884 const LIB_SYMBOL* templatePart = loadSymdef( symID );
885 wxCHECK( templatePart, /*void*/ );
886
887 auto ownedPart = std::make_unique<LIB_SYMBOL>( *templatePart );
888 kiPart = ownedPart.get();
889 m_ownedSymbols.push_back( std::move( ownedPart ) );
890
891 kiPart->SetGlobalPower();
892 kiPart->SetName( libPartName );
893 kiPart->GetValueField().SetText( symbolInstanceNetName );
894 kiPart->SetShowPinNames( false );
895 kiPart->SetShowPinNumbers( false );
896
897 std::vector<SCH_PIN*> pins = kiPart->GetGraphicalPins( 0, 0 );
898 wxCHECK( pins.size() == 1, /*void*/ );
899
900 pins.at( 0 )->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
901 pins.at( 0 )->SetName( symbolInstanceNetName );
902
903 if( libSymDef.TextLocations.find( SIGNALNAME_ORIGIN_ATTRID )
904 != libSymDef.TextLocations.end() )
905 {
906 TEXT_LOCATION& txtLoc =
908
909 VECTOR2I valPos = getKiCadLibraryPoint( txtLoc.Position, libSymDef.Origin );
910
911 kiPart->GetValueField().SetPosition( valPos );
912 kiPart->GetValueField().SetVisible( true );
913 }
914 else
915 {
916 kiPart->GetValueField().SetVisible( false );
917 }
918
919 kiPart->GetReferenceField().SetText( "#PWR" );
920 kiPart->GetReferenceField().SetVisible( false );
921 m_loadedSymbols.push_back( kiPart );
922 m_powerSymLibMap.insert( { libPartName, kiPart } );
923 }
924 else
925 {
926 kiPart = m_powerSymLibMap.at( libPartName );
927 wxASSERT( kiPart->GetValueField().GetText() == symbolInstanceNetName );
928 }
929
930 std::unique_ptr<LIB_SYMBOL> scaledPart(
932
933 EDA_ANGLE returnedOrient = ANGLE_0;
934 SCH_SYMBOL* symbol = loadSchematicSymbol( sym, *scaledPart, returnedOrient );
935 m_powerSymMap.insert( { sym.ID, symbol } );
936 }
937 else if( sym.SymbolVariant.Type == SYMBOLVARIANT::TYPE::SIGNALREF )
938 {
939 // There should only be one pin and we'll use that to set the position
940 TERMINAL& symbolTerminal = libSymDef.Terminals.begin()->second;
941 VECTOR2I terminalPosOffset = symbolTerminal.Position - libSymDef.Origin;
942 EDA_ANGLE rotate = getAngle( sym.OrientAngle );
943
944 if( sym.Mirror )
945 rotate += ANGLE_180;
946
947 RotatePoint( terminalPosOffset, -rotate );
948
949 SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL;
950 netLabel->SetPosition( getKiCadPoint( VECTOR2I( sym.Origin.x, sym.Origin.y ) + terminalPosOffset ) );
951 netLabel->SetText( "***UNKNOWN NET****" ); // This should be later updated when we load the netlist
952 netLabel->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 50 ), schIUScale.MilsToIU( 50 ) ) );
953
954 SYMDEF_SCM symbolDef = Library.SymbolDefinitions.at( sym.SymdefID );
955
956 if( symbolDef.TextLocations.count( LINK_ORIGIN_ATTRID ) )
957 {
958 TEXT_LOCATION linkOrigin = symbolDef.TextLocations.at( LINK_ORIGIN_ATTRID );
959 applyTextSettings( netLabel, linkOrigin.TextCodeID, linkOrigin.Alignment,
960 linkOrigin.Justification );
961 }
962
963 netLabel->SetSpinStyle( getSpinStyle( sym.OrientAngle, sym.Mirror ) );
964
965 if( libSymDef.Alternate.Lower().Contains( "in" ) )
967 else if( libSymDef.Alternate.Lower().Contains( "bi" ) )
969 else if( libSymDef.Alternate.Lower().Contains( "out" ) )
971 else
973
974 SCH_SCREEN* screen = m_sheetMap.at( sym.LayerID )->GetScreen();
975
976 // autoplace intersheet refs
977 netLabel->AutoplaceFields( screen, AUTOPLACE_AUTO );
978
979 screen->Append( netLabel );
980 m_globalLabelsMap.insert( { sym.ID, netLabel } );
981 }
982 else
983 {
984 wxASSERT_MSG( false, "Unknown Symbol Variant." );
985 }
986 }
987 else
988 {
989 m_reporter->Report( wxString::Format( _( "Symbol ID '%s' is of an unknown type. It is neither a "
990 "symbol or a net power / symbol. The symbol was not loaded." ),
991 sym.ID ),
993 }
994
995 if( sym.ScaleRatioDenominator != 1 || sym.ScaleRatioNumerator != 1 )
996 {
997 wxString symbolName = sym.ComponentRef.Designator;
998
999 if( symbolName.empty() )
1000 symbolName = wxString::Format( "ID: %s", sym.ID );
1001 else
1002 symbolName += sym.GateID;
1003
1004 m_reporter->Report( wxString::Format( _( "Symbol '%s' is scaled in the original CADSTAR schematic "
1005 "but this is not supported in KiCad. When the symbol is "
1006 "reloaded from the library, it will revert to the original "
1007 "1:1 scale." ),
1008 symbolName,
1009 sym.PartRef.RefID ),
1011 }
1012 }
1013}
1014
1015
1017{
1018 for( std::pair<BUS_ID, BUS> busPair : Schematic.Buses )
1019 {
1020 BUS bus = busPair.second;
1021 bool firstPt = true;
1022 VERTEX last;
1023
1024 if( bus.LayerID != wxT( "NO_SHEET" ) )
1025 {
1026 SCH_SCREEN* screen = m_sheetMap.at( bus.LayerID )->GetScreen();
1027 std::shared_ptr<BUS_ALIAS> kiBusAlias = std::make_shared<BUS_ALIAS>();
1028
1029 kiBusAlias->SetName( bus.Name );
1030 screen->AddBusAlias( kiBusAlias );
1031 m_busesMap.insert( { bus.ID, kiBusAlias } );
1032
1033 SCH_LABEL* label = new SCH_LABEL();
1034
1035 wxString busname = HandleTextOverbar( bus.Name );
1036
1037 label->SetText( wxT( "{" ) + busname + wxT( "}" ) );
1038 label->SetVisible( true );
1039 screen->Append( label );
1040
1041 SHAPE_LINE_CHAIN busLineChain; // to compute nearest segment to bus label
1042
1043 for( const VERTEX& cur : bus.Shape.Vertices )
1044 {
1045 busLineChain.Append( getKiCadPoint( cur.End ) );
1046
1047 if( firstPt )
1048 {
1049 last = cur;
1050 firstPt = false;
1051
1052 if( !bus.HasBusLabel )
1053 {
1054 // Add a bus label on the starting point if the original CADSTAR design
1055 // does not have an explicit label
1056 label->SetPosition( getKiCadPoint( last.End ) );
1057 }
1058
1059 continue;
1060 }
1061
1062
1063 SCH_LINE* kiBus = new SCH_LINE();
1064
1065 kiBus->SetStartPoint( getKiCadPoint( last.End ) );
1066 kiBus->SetEndPoint( getKiCadPoint( cur.End ) );
1067 kiBus->SetLayer( LAYER_BUS );
1068 kiBus->SetLineWidth( getLineThickness( bus.LineCodeID ) );
1069 screen->Append( kiBus );
1070
1071 last = cur;
1072 }
1073
1074 if( bus.HasBusLabel )
1075 {
1076 //lets find the closest point in the busline to the label
1077 VECTOR2I busLabelLoc = getKiCadPoint( bus.BusLabel.Position );
1078 VECTOR2I nearestPt = busLineChain.NearestPoint( busLabelLoc );
1079
1080 label->SetPosition( nearestPt );
1081
1083 bus.BusLabel.Justification );
1084
1085 // Re-set bus name as it might have been "double-escaped" after applyTextSettings
1086 label->SetText( wxT( "{" ) + busname + wxT( "}" ) );
1087
1088 // Note orientation of the bus label will be determined in loadNets
1089 // (the position of the wire will determine how best to place the bus label)
1090 }
1091 }
1092 }
1093}
1094
1095
1097{
1098 for( std::pair<NET_ID, NET_SCH> netPair : Schematic.Nets )
1099 {
1100 NET_SCH net = netPair.second;
1101 wxString netName = net.Name;
1102 std::map<NETELEMENT_ID, SCH_LABEL*> netlabels;
1103
1104 if( netName.IsEmpty() )
1105 netName = wxString::Format( "$%ld", net.SignalNum );
1106
1107 netName = HandleTextOverbar( netName );
1108
1109 for( std::pair<NETELEMENT_ID, NET_SCH::SYM_TERM> terminalPair : net.Terminals )
1110 {
1111 NET_SCH::SYM_TERM netTerm = terminalPair.second;
1112
1113 if( m_powerSymMap.find( netTerm.SymbolID ) != m_powerSymMap.end() )
1114 {
1115 SCH_FIELD* val = m_powerSymMap.at( netTerm.SymbolID )->GetField( FIELD_T::VALUE );
1116 val->SetText( netName );
1117 val->SetBold( false );
1118 val->SetVisible( false );
1119
1120 if( netTerm.HasNetLabel )
1121 {
1122 val->SetVisible( true );
1123 val->SetPosition( getKiCadPoint( netTerm.NetLabel.Position ) );
1124
1125 applyTextSettings( val, netTerm.NetLabel.TextCodeID, netTerm.NetLabel.Alignment,
1126 netTerm.NetLabel.Justification, netTerm.NetLabel.OrientAngle,
1127 netTerm.NetLabel.Mirror );
1128 }
1129 }
1130 else if( m_globalLabelsMap.find( netTerm.SymbolID ) != m_globalLabelsMap.end() )
1131 {
1132 m_globalLabelsMap.at( netTerm.SymbolID )->SetText( netName );
1133
1134 LAYER_ID sheet = Schematic.Symbols.at( netTerm.SymbolID ).LayerID;
1135
1136 if( m_sheetMap.count( sheet ) )
1137 {
1138 SCH_SCREEN* screen = m_sheetMap.at( sheet )->GetScreen();
1139
1140 // autoplace intersheet refs again since we've changed the name
1141 m_globalLabelsMap.at( netTerm.SymbolID )->AutoplaceFields( screen, AUTOPLACE_AUTO );
1142 }
1143 }
1144 else if( !net.Name.IsEmpty() && Schematic.Symbols.count( netTerm.SymbolID )
1145 && netTerm.HasNetLabel )
1146 {
1147 // This is a named net that connects to a schematic symbol pin - we need to put a label
1148 SCH_LABEL* label = new SCH_LABEL();
1149 label->SetText( netName );
1150
1151 POINT pinLocation = getLocationOfNetElement( net, netTerm.ID );
1152 label->SetPosition( getKiCadPoint( pinLocation ) );
1153 label->SetVisible( true );
1154
1155 applyTextSettings( label, netTerm.NetLabel.TextCodeID, netTerm.NetLabel.Alignment,
1156 netTerm.NetLabel.Justification );
1157
1158 netlabels.insert( { netTerm.ID, label } );
1159
1160 LAYER_ID sheet = Schematic.Symbols.at( netTerm.SymbolID ).LayerID;
1161 m_sheetMap.at( sheet )->GetScreen()->Append( label );
1162 }
1163 }
1164
1165 auto getHierarchicalLabel =
1166 [&]( const NETELEMENT_ID& aNode ) -> SCH_HIERLABEL*
1167 {
1168 if( aNode.Contains( "BLKT" ) )
1169 {
1170 NET_SCH::BLOCK_TERM blockTerm = net.BlockTerminals.at( aNode );
1171 BLOCK_PIN_ID blockPinID = std::make_pair( blockTerm.BlockID, blockTerm.TerminalID );
1172
1173 if( m_sheetPinMap.find( blockPinID ) != m_sheetPinMap.end() )
1174 return m_sheetPinMap.at( blockPinID );
1175 }
1176
1177 return nullptr;
1178 };
1179
1180 //Add net name to all hierarchical pins (block terminals in CADSTAR)
1181 for( std::pair<NETELEMENT_ID, NET_SCH::BLOCK_TERM> blockPair : net.BlockTerminals )
1182 {
1183 SCH_HIERLABEL* label = getHierarchicalLabel( blockPair.first );
1184
1185 if( label )
1186 label->SetText( netName );
1187 }
1188
1189 // Load all bus entries and add net label if required
1190 for( std::pair<NETELEMENT_ID, NET_SCH::BUS_TERM> busPair : net.BusTerminals )
1191 {
1192 NET_SCH::BUS_TERM busTerm = busPair.second;
1193 BUS bus = Schematic.Buses.at( busTerm.BusID );
1194
1195 if( !alg::contains( m_busesMap.at( bus.ID )->Members(), netName ) )
1196 m_busesMap.at( bus.ID )->AddMember( netName );
1197
1198 SCH_BUS_WIRE_ENTRY* busEntry =
1199 new SCH_BUS_WIRE_ENTRY( getKiCadPoint( busTerm.FirstPoint ), false );
1200
1201 VECTOR2I size =
1202 getKiCadPoint( busTerm.SecondPoint ) - getKiCadPoint( busTerm.FirstPoint );
1203 busEntry->SetSize( VECTOR2I( size.x, size.y ) );
1204
1205 m_sheetMap.at( bus.LayerID )->GetScreen()->Append( busEntry );
1206
1207 // Always add a label at bus terminals to ensure connectivity.
1208 // If the original design does not have a label, just make it very small
1209 // to keep connectivity but make the design look visually similar to
1210 // the original.
1211 SCH_LABEL* label = new SCH_LABEL();
1212 label->SetText( netName );
1213 label->SetPosition( getKiCadPoint( busTerm.SecondPoint ) );
1214 label->SetVisible( true );
1215
1216 if( busTerm.HasNetLabel )
1217 {
1218 applyTextSettings( label, busTerm.NetLabel.TextCodeID, busTerm.NetLabel.Alignment,
1219 busTerm.NetLabel.Justification );
1220 }
1221 else
1222 {
1224 }
1225
1226 netlabels.insert( { busTerm.ID, label } );
1227 m_sheetMap.at( bus.LayerID )->GetScreen()->Append( label );
1228 }
1229
1230 for( std::pair<NETELEMENT_ID, NET_SCH::DANGLER> danglerPair : net.Danglers )
1231 {
1232 NET_SCH::DANGLER dangler = danglerPair.second;
1233
1234 SCH_LABEL* label = new SCH_LABEL();
1235 label->SetPosition( getKiCadPoint( dangler.Position ) );
1236 label->SetVisible( true );
1237
1238 if( dangler.HasNetLabel )
1239 {
1240 applyTextSettings( label, dangler.NetLabel.TextCodeID, dangler.NetLabel.Alignment,
1241 dangler.NetLabel.Justification );
1242 }
1243
1244 label->SetText( netName ); // set text after applying settings to avoid double-escaping
1245 netlabels.insert( { dangler.ID, label } );
1246
1247 m_sheetMap.at( dangler.LayerID )->GetScreen()->Append( label );
1248 }
1249
1250 for( NET_SCH::CONNECTION_SCH conn : net.Connections )
1251 {
1252 if( conn.LayerID == wxT( "NO_SHEET" ) )
1253 continue; // No point loading virtual connections. KiCad handles that internally
1254
1255 POINT start = getLocationOfNetElement( net, conn.StartNode );
1256 POINT end = getLocationOfNetElement( net, conn.EndNode );
1257
1258 if( start.x == UNDEFINED_VALUE || end.x == UNDEFINED_VALUE )
1259 continue;
1260
1261 // Connections in CADSTAR are always implied between symbols even if the route
1262 // doesn't start and end exactly at the connection points
1263 if( conn.Path.size() < 1 || conn.Path.front().End != start )
1264 conn.Path.insert( conn.Path.begin(), VERTEX( VERTEX_TYPE::VT_POINT, start ) );
1265
1266 if( conn.Path.size() < 2 || conn.Path.back().End != end )
1267 conn.Path.push_back( VERTEX( VERTEX_TYPE::VT_POINT, end ) );
1268
1269 bool firstPt = true;
1270 bool secondPt = false;
1271 VECTOR2I last;
1272 SCH_LINE* wire = nullptr;
1273
1274 SHAPE_LINE_CHAIN wireChain; // Create a temp. line chain representing the connection
1275
1276 auto cadstarToKicadPoint = [this]( const VECTOR2I& aPoint ) -> VECTOR2I
1277 {
1278 return getKiCadPoint( aPoint );
1279 };
1280
1281 for( const VERTEX& vertex : conn.Path )
1282 vertex.AppendToChain( &wireChain, cadstarToKicadPoint, ARC_ACCURACY );
1283
1284 // AUTO-FIX SHEET PINS
1285 //--------------------
1286 // KiCad constrains the sheet pin on the edge of the sheet object whereas in
1287 // CADSTAR it can be anywhere. Let's find the intersection of the wires with the sheet
1288 // and place the hierarchical
1289 std::vector<NETELEMENT_ID> nodes;
1290 nodes.push_back( conn.StartNode );
1291 nodes.push_back( conn.EndNode );
1292
1293 for( const NETELEMENT_ID& node : nodes )
1294 {
1295 SCH_HIERLABEL* sheetPin = getHierarchicalLabel( node );
1296
1297 if( sheetPin )
1298 {
1299 if( sheetPin->Type() == SCH_SHEET_PIN_T
1300 && SCH_SHEET::ClassOf( sheetPin->GetParent() ) )
1301 {
1302 SCH_SHEET* parentSheet = static_cast<SCH_SHEET*>( sheetPin->GetParent() );
1303 VECTOR2I sheetSize = parentSheet->GetSize();
1304 VECTOR2I sheetPosition = parentSheet->GetPosition();
1305
1306 int leftSide = sheetPosition.x;
1307 int rightSide = sheetPosition.x + sheetSize.x;
1308 int topSide = sheetPosition.y;
1309 int botSide = sheetPosition.y + sheetSize.y;
1310
1311 SHAPE_LINE_CHAIN sheetEdge;
1312
1313 sheetEdge.Append( leftSide, topSide );
1314 sheetEdge.Append( rightSide, topSide );
1315 sheetEdge.Append( rightSide, botSide );
1316 sheetEdge.Append( leftSide, botSide );
1317 sheetEdge.Append( leftSide, topSide );
1318
1319 SHAPE_LINE_CHAIN::INTERSECTIONS wireToSheetIntersects;
1320
1321 if( !wireChain.Intersect( sheetEdge, wireToSheetIntersects ) )
1322 {
1323 // The block terminal is outside the block shape in the original
1324 // CADSTAR design. Since KiCad's Sheet Pin will already be constrained
1325 // on the edge, we will simply join to it with a straight line.
1326 if( node == conn.StartNode )
1327 wireChain = wireChain.Reverse();
1328
1329 wireChain.Append( sheetPin->GetPosition() );
1330
1331 if( node == conn.StartNode )
1332 wireChain = wireChain.Reverse();
1333 }
1334 else
1335 {
1336 // The block terminal is either inside or on the shape edge. Lets use
1337 // the first intersection point.
1338 VECTOR2I intsctPt = wireToSheetIntersects.at( 0 ).p;
1339 int intsctIndx = wireChain.FindSegment( intsctPt );
1340 wxASSERT_MSG( intsctIndx != -1, "Can't find intersecting segment" );
1341
1342 if( node == conn.StartNode )
1343 wireChain.Replace( 0, intsctIndx, intsctPt );
1344 else
1345 wireChain.Replace( intsctIndx + 1, /*end index*/ -1, intsctPt );
1346
1347 sheetPin->SetPosition( intsctPt );
1348 }
1349 }
1350 }
1351 }
1352
1353 auto fixNetLabelsAndSheetPins =
1354 [&]( const EDA_ANGLE& aWireAngle, NETELEMENT_ID& aNetEleID )
1355 {
1356 SPIN_STYLE spin = getSpinStyle( aWireAngle );
1357
1358 if( netlabels.find( aNetEleID ) != netlabels.end() )
1359 netlabels.at( aNetEleID )->SetSpinStyle( spin.MirrorY() );
1360
1361 SCH_HIERLABEL* sheetPin = getHierarchicalLabel( aNetEleID );
1362
1363 if( sheetPin )
1364 sheetPin->SetSpinStyle( spin.MirrorX() );
1365 };
1366
1367 // Now we can load the wires and fix the label orientations
1368 for( const VECTOR2I& pt : wireChain.CPoints() )
1369 {
1370 if( firstPt )
1371 {
1372 last = pt;
1373 firstPt = false;
1374 secondPt = true;
1375 continue;
1376 }
1377
1378 if( secondPt )
1379 {
1380 secondPt = false;
1381
1382 EDA_ANGLE wireAngle( last - pt );
1383 fixNetLabelsAndSheetPins( wireAngle, conn.StartNode );
1384 }
1385
1386 wire = new SCH_LINE();
1387
1388 wire->SetStartPoint( last );
1389 wire->SetEndPoint( pt );
1390 wire->SetLayer( LAYER_WIRE );
1391
1392 if( !conn.ConnectionLineCode.IsEmpty() )
1393 wire->SetLineWidth( getLineThickness( conn.ConnectionLineCode ) );
1394
1395 last = pt;
1396
1397 m_sheetMap.at( conn.LayerID )->GetScreen()->Append( wire );
1398 }
1399
1400 //Fix labels on the end wire
1401 if( wire )
1402 {
1403 EDA_ANGLE wireAngle( wire->GetEndPoint() - wire->GetStartPoint() );
1404 fixNetLabelsAndSheetPins( wireAngle, conn.EndNode );
1405 }
1406 }
1407
1408 for( std::pair<NETELEMENT_ID, NET_SCH::JUNCTION_SCH> juncPair : net.Junctions )
1409 {
1410 NET_SCH::JUNCTION_SCH junc = juncPair.second;
1411
1412 SCH_JUNCTION* kiJunc = new SCH_JUNCTION();
1413
1414 kiJunc->SetPosition( getKiCadPoint( junc.Location ) );
1415 m_sheetMap.at( junc.LayerID )->GetScreen()->Append( kiJunc );
1416
1417 if( junc.HasNetLabel )
1418 {
1419 // In CADSTAR the label can be placed anywhere, but in KiCad it has to be placed
1420 // in the same location as the junction for it to be connected to it.
1421 SCH_LABEL* label = new SCH_LABEL();
1422 label->SetText( netName );
1423 label->SetPosition( getKiCadPoint( junc.Location ) );
1424 label->SetVisible( true );
1425
1426 EDA_ANGLE labelAngle = getAngle( junc.NetLabel.OrientAngle );
1427 SPIN_STYLE spin = getSpinStyle( labelAngle );
1428
1429 label->SetSpinStyle( spin );
1430
1431 m_sheetMap.at( junc.LayerID )->GetScreen()->Append( label );
1432 }
1433 }
1434 }
1435}
1436
1437
1439{
1440 for( std::pair<FIGURE_ID, FIGURE> figPair : Schematic.Figures )
1441 {
1442 FIGURE fig = figPair.second;
1443
1444 loadFigure( fig, fig.LayerID, LAYER_NOTES );
1445 }
1446}
1447
1448
1450{
1451 for( std::pair<TEXT_ID, TEXT> textPair : Schematic.Texts )
1452 {
1453 TEXT txt = textPair.second;
1454
1455 SCH_TEXT* kiTxt = getKiCadSchText( txt );
1456 loadItemOntoKiCadSheet( txt.LayerID, kiTxt );
1457 }
1458}
1459
1460
1462{
1463 for( std::pair<DOCUMENTATION_SYMBOL_ID, DOCUMENTATION_SYMBOL> docSymPair :
1464 Schematic.DocumentationSymbols )
1465 {
1466 DOCUMENTATION_SYMBOL docSym = docSymPair.second;
1467
1468 if( Library.SymbolDefinitions.find( docSym.SymdefID ) == Library.SymbolDefinitions.end() )
1469 {
1470 m_reporter->Report( wxString::Format( _( "Documentation Symbol '%s' refers to symbol definition "
1471 "ID '%s' which does not exist in the library. The symbol "
1472 "was not loaded." ),
1473 docSym.ID,
1474 docSym.SymdefID ),
1476 continue;
1477 }
1478
1479 SYMDEF_SCM docSymDef = Library.SymbolDefinitions.at( docSym.SymdefID );
1480 VECTOR2I moveVector = getKiCadPoint( docSym.Origin ) - getKiCadPoint( docSymDef.Origin );
1481 EDA_ANGLE rotationAngle = getAngle( docSym.OrientAngle );
1482 double scalingFactor = (double) docSym.ScaleRatioNumerator
1483 / (double) docSym.ScaleRatioDenominator;
1484 VECTOR2I centreOfTransform = getKiCadPoint( docSymDef.Origin );
1485 bool mirrorInvert = docSym.Mirror;
1486
1487 for( std::pair<FIGURE_ID, FIGURE> figPair : docSymDef.Figures )
1488 {
1489 FIGURE fig = figPair.second;
1490
1491 loadFigure( fig, docSym.LayerID, LAYER_NOTES, moveVector, rotationAngle, scalingFactor,
1492 centreOfTransform, mirrorInvert );
1493 }
1494
1495 for( std::pair<TEXT_ID, TEXT> textPair : docSymDef.Texts )
1496 {
1497 TEXT txt = textPair.second;
1498
1499 txt.Mirror = ( txt.Mirror ) ? !mirrorInvert : mirrorInvert;
1500 txt.OrientAngle = docSym.OrientAngle - txt.OrientAngle;
1501
1502 SCH_TEXT* kiTxt = getKiCadSchText( txt );
1503
1504 VECTOR2I newPosition = applyTransform( kiTxt->GetPosition(), moveVector, rotationAngle,
1505 scalingFactor, centreOfTransform, mirrorInvert );
1506
1507 int newTxtWidth = KiROUND( kiTxt->GetTextWidth() * scalingFactor );
1508 int newTxtHeight = KiROUND( kiTxt->GetTextHeight() * scalingFactor );
1509 int newTxtThickness = KiROUND( kiTxt->GetTextThickness() * scalingFactor );
1510
1511 kiTxt->SetPosition( newPosition );
1512 kiTxt->SetTextWidth( newTxtWidth );
1513 kiTxt->SetTextHeight( newTxtHeight );
1514 kiTxt->SetTextThickness( newTxtThickness );
1515
1516 loadItemOntoKiCadSheet( docSym.LayerID, kiTxt );
1517 }
1518 }
1519}
1520
1521
1523{
1524 auto findAndReplaceTextField =
1525 [&]( TEXT_FIELD_NAME aField, wxString aValue )
1526 {
1527 if( m_context.TextFieldToValuesMap.find( aField ) != m_context.TextFieldToValuesMap.end() )
1528 {
1529 if( m_context.TextFieldToValuesMap.at( aField ) != aValue )
1530 {
1531 m_context.TextFieldToValuesMap.at( aField ) = aValue;
1532 m_context.InconsistentTextFields.insert( aField );
1533 return false;
1534 }
1535 }
1536 else
1537 {
1538 m_context.TextFieldToValuesMap.insert( { aField, aValue } );
1539 }
1540
1541 return true;
1542 };
1543
1544 PROJECT* pj = &m_schematic->Project();
1545
1546 if( pj )
1547 {
1548 std::map<wxString, wxString>& txtVars = pj->GetTextVars();
1549
1550 // Most of the design text fields can be derived from other elements
1551 if( Schematic.VariantHierarchy.Variants.size() > 0 )
1552 {
1553 VARIANT loadedVar = Schematic.VariantHierarchy.Variants.begin()->second;
1554
1555 findAndReplaceTextField( TEXT_FIELD_NAME::VARIANT_NAME, loadedVar.Name );
1556 findAndReplaceTextField( TEXT_FIELD_NAME::VARIANT_DESCRIPTION, loadedVar.Description );
1557 }
1558
1559 findAndReplaceTextField( TEXT_FIELD_NAME::DESIGN_TITLE, Header.JobTitle );
1560
1561 for( std::pair<TEXT_FIELD_NAME, wxString> txtvalue : m_context.TextFieldToValuesMap )
1562 {
1563 wxString varName = CADSTAR_TO_KICAD_FIELDS.at( txtvalue.first );
1564 wxString varValue = txtvalue.second;
1565
1566 txtVars.insert( { varName, varValue } );
1567 }
1568
1569 for( std::pair<wxString, wxString> txtvalue : m_context.FilenamesToTextMap )
1570 {
1571 wxString varName = txtvalue.first;
1572 wxString varValue = txtvalue.second;
1573
1574 txtVars.insert( { varName, varValue } );
1575 }
1576 }
1577 else
1578 {
1579 m_reporter->Report( _( "Text Variables could not be set as there is no project attached." ),
1581 }
1582}
1583
1584
1586 LIB_SYMBOL* aKiCadSymbol )
1587{
1588 // First Check if field already exists
1589 if( SCH_FIELD* existingField = aKiCadSymbol->GetField( aFieldName ) )
1590 return existingField;
1591
1592 SCH_FIELD* newfield = new SCH_FIELD( aKiCadSymbol, FIELD_T::USER, aFieldName );
1593 newfield->SetVisible( false );
1594 aKiCadSymbol->AddField( newfield );
1595 /*
1596 @todo we should load that a field is a URL by checking if it starts with "Link"
1597 e.g.:
1598 if( aFieldName.Lower().StartsWith( "link" ) )
1599 newfield->SetAsURL*/
1600
1601 return newfield;
1602}
1603
1604
1606{
1607 wxCHECK( Library.SymbolDefinitions.find( aSymdefID ) != Library.SymbolDefinitions.end(), nullptr );
1608
1609 if( m_symDefMap.count( aSymdefID ) )
1610 return m_symDefMap.at( aSymdefID ).get(); // return a non-owning ptr
1611
1612 SYMDEF_SCM csSym = Library.SymbolDefinitions.at( aSymdefID );
1613 std::unique_ptr<LIB_SYMBOL> kiSym = std::make_unique<LIB_SYMBOL>( csSym.BuildLibName() );
1614 const int gateNumber = 1; // Always load to gate "A" - we will change the unit later
1615
1616 // Load Graphical Figures
1617 for( std::pair<FIGURE_ID, FIGURE> figPair : csSym.Figures )
1618 {
1619 FIGURE fig = figPair.second;
1620 int lineThickness = getLineThickness( fig.LineCodeID );
1621 LINE_STYLE linestyle = getLineStyle( fig.LineCodeID );
1622
1623 if( fig.Shape.Type == SHAPE_TYPE::OPENSHAPE )
1624 {
1625 loadLibrarySymbolShapeVertices( fig.Shape.Vertices, csSym.Origin, kiSym.get(), gateNumber,
1626 lineThickness, linestyle );
1627 }
1628 else
1629 {
1631
1632 shape->SetPolyShape( fig.Shape.ConvertToPolySet( [&]( const VECTOR2I& aPt )
1633 {
1634 return getKiCadLibraryPoint( aPt, csSym.Origin );
1635 },
1636 ARC_ACCURACY ) );
1637
1638 shape->SetUnit( gateNumber );
1639
1640 shape->SetStroke( STROKE_PARAMS( lineThickness, linestyle ) );
1641
1642 if( fig.Shape.Type == SHAPE_TYPE::SOLID )
1644 else if( fig.Shape.Type == SHAPE_TYPE::OUTLINE )
1645 shape->SetFillMode( FILL_T::NO_FILL );
1646 else if( fig.Shape.Type == SHAPE_TYPE::HATCHED ) // We don't have an equivalent
1648
1649 kiSym->AddDrawItem( shape );
1650 }
1651 }
1652
1653 PINNUM_TO_TERMINAL_MAP pinNumToTerminals;
1654
1655 // Load Pins
1656 for( std::pair<TERMINAL_ID, TERMINAL> termPair : csSym.Terminals )
1657 {
1658 TERMINAL term = termPair.second;
1659 wxString pinNum = wxString::Format( "%ld", term.ID );
1660 wxString pinName = wxEmptyString;
1661 std::unique_ptr<SCH_PIN> pin = std::make_unique<SCH_PIN>( kiSym.get() );
1662
1663 // Assume passive pin for now (we will set it later once we load the parts)
1665
1666 pin->SetPosition( getKiCadLibraryPoint( term.Position, csSym.Origin ) );
1667 pin->SetLength( 0 ); //CADSTAR Pins are just a point (have no length)
1668 pin->SetShape( GRAPHIC_PINSHAPE::LINE );
1669 pin->SetUnit( gateNumber );
1670 pin->SetNumber( pinNum );
1671 pin->SetName( pinName );
1672
1673 // TC0 is the default CADSTAR text size for name/number if none specified
1674 int pinNumberHeight = getTextHeightFromTextCode( wxT( "TC0" ) );
1675 int pinNameHeight = getTextHeightFromTextCode( wxT( "TC0" ) );
1676
1677 if( csSym.PinNumberLocations.count( term.ID ) )
1678 {
1679 PIN_NUM_LABEL_LOC pinNumLocation = csSym.PinNumberLocations.at( term.ID );
1680 pinNumberHeight = getTextHeightFromTextCode( pinNumLocation.TextCodeID );
1681 }
1682
1683 if( csSym.PinLabelLocations.count( term.ID ) )
1684 {
1685 PIN_NUM_LABEL_LOC pinNameLocation = csSym.PinLabelLocations.at( term.ID );
1686 pinNameHeight = getTextHeightFromTextCode( pinNameLocation.TextCodeID );
1687 }
1688
1689 pin->SetNumberTextSize( pinNumberHeight );
1690 pin->SetNameTextSize( pinNameHeight );
1691
1692 pinNumToTerminals.insert( { pin->GetNumber(), term.ID } );
1693 kiSym->AddDrawItem( pin.release() );
1694 }
1695
1696 m_symDefTerminalsMap.insert( { aSymdefID, pinNumToTerminals } );
1697 fixUpLibraryPins( kiSym.get(), gateNumber );
1698
1699
1700 // Load Text items
1701 for( std::pair<TEXT_ID, TEXT> textPair : csSym.Texts )
1702 {
1703 TEXT csText = textPair.second;
1704 VECTOR2I pos = getKiCadLibraryPoint( csText.Position, csSym.Origin );
1705 auto libtext = std::make_unique<SCH_TEXT>( pos, csText.Text, LAYER_DEVICE );
1706
1707 libtext->SetUnit( gateNumber );
1708 libtext->SetPosition( getKiCadLibraryPoint( csText.Position, csSym.Origin ) );
1709 libtext->SetMultilineAllowed( true ); // temporarily so that we calculate bbox correctly
1710
1711 applyTextSettings( libtext.get(), csText.TextCodeID, csText.Alignment, csText.Justification,
1712 csText.OrientAngle, csText.Mirror );
1713
1714 // Split out multi line text items into individual text elements
1715 if( csText.Text.Contains( "\n" ) )
1716 {
1717 wxArrayString strings;
1718 wxStringSplit( csText.Text, strings, '\n' );
1719
1720 for( size_t ii = 0; ii < strings.size(); ++ii )
1721 {
1722 BOX2I bbox = libtext->GetTextBox( nullptr, ii );
1723 VECTOR2I linePos = { bbox.GetLeft(), -bbox.GetBottom() };
1724
1725 RotatePoint( linePos, libtext->GetTextPos(), -libtext->GetTextAngle() );
1726
1727 SCH_TEXT* textLine = static_cast<SCH_TEXT*>( libtext->Duplicate( IGNORE_PARENT_GROUP ) );
1728 textLine->SetText( strings[ii] );
1731 textLine->SetTextPos( linePos );
1732
1733 // Multiline text not allowed in LIB_TEXT
1734 textLine->SetMultilineAllowed( false );
1735 kiSym->AddDrawItem( textLine );
1736 }
1737 }
1738 else
1739 {
1740 // Multiline text not allowed in LIB_TEXT
1741 libtext->SetMultilineAllowed( false );
1742 kiSym->AddDrawItem( libtext.release() );
1743 }
1744 }
1745
1746 // CADSTAR uses TC1 when fields don't have explicit text/attribute location
1747 static const TEXTCODE_ID defaultTextCode = "TC1";
1748
1749 // Load field locations (Attributes in CADSTAR)
1750
1751 // Symbol name (e.g. R1)
1752 if( csSym.TextLocations.count( SYMBOL_NAME_ATTRID ) )
1753 {
1754 TEXT_LOCATION& textLoc = csSym.TextLocations.at( SYMBOL_NAME_ATTRID );
1755 applyToLibraryFieldAttribute( textLoc, csSym.Origin, &kiSym->GetReferenceField() );
1756 }
1757 else
1758 {
1759 applyTextCodeIfExists( &kiSym->GetReferenceField(), defaultTextCode );
1760 }
1761
1762 // Always add the part name field (even if it doesn't have a specific location defined)
1763 SCH_FIELD* partField = addNewFieldToSymbol( PartNameFieldName, kiSym.get() );
1764 wxCHECK( partField, nullptr );
1765 wxASSERT( partField->GetName() == PartNameFieldName );
1766
1767 if( csSym.TextLocations.count( PART_NAME_ATTRID ) )
1768 {
1769 TEXT_LOCATION& textLoc = csSym.TextLocations.at( PART_NAME_ATTRID );
1770 applyToLibraryFieldAttribute( textLoc, csSym.Origin, partField );
1771 }
1772 else
1773 {
1774 applyTextCodeIfExists( partField, defaultTextCode );
1775 }
1776
1777 partField->SetVisible( SymbolPartNameColor.IsVisible );
1778
1779
1780 for( auto& [attributeId, textLocation] : csSym.TextLocations )
1781 {
1782 if( attributeId == PART_NAME_ATTRID || attributeId == SYMBOL_NAME_ATTRID
1783 || attributeId == SIGNALNAME_ORIGIN_ATTRID || attributeId == LINK_ORIGIN_ATTRID )
1784 {
1785 continue;
1786 }
1787
1788 wxString attributeName = getAttributeName( attributeId );
1789 SCH_FIELD* field = addNewFieldToSymbol( attributeName, kiSym.get() );
1790 applyToLibraryFieldAttribute( textLocation, csSym.Origin, field );
1791 }
1792
1793
1794 for( auto& [attributeId, attrValue] : csSym.AttributeValues )
1795 {
1796 if( attributeId == PART_NAME_ATTRID || attributeId == SYMBOL_NAME_ATTRID
1797 || attributeId == SIGNALNAME_ORIGIN_ATTRID || attributeId == LINK_ORIGIN_ATTRID )
1798 {
1799 continue;
1800 }
1801
1802 wxString attributeName = getAttributeName( attributeId );
1803 SCH_FIELD* field = addNewFieldToSymbol( attributeName, kiSym.get() );
1804
1805 if( attrValue.HasLocation )
1806 applyToLibraryFieldAttribute( attrValue.AttributeLocation, csSym.Origin, field );
1807 else
1808 applyTextCodeIfExists( field, defaultTextCode );
1809 }
1810
1811
1812 m_symDefMap.insert( { aSymdefID, std::move( kiSym ) } );
1813
1814 return m_symDefMap.at( aSymdefID ).get(); // return a non-owning ptr
1815}
1816
1817
1819 const PART& aCadstarPart,
1820 const GATE_ID& aGateID,
1821 LIB_SYMBOL* aSymbol )
1822{
1823 wxCHECK( Library.SymbolDefinitions.find( aSymdefID ) != Library.SymbolDefinitions.end(), /*void*/ );
1824
1825 std::unique_ptr<LIB_SYMBOL> kiSymDef( loadSymdef( aSymdefID )->Duplicate() );
1826 wxCHECK( kiSymDef, /*void*/ );
1827
1828 // Update the pin numbers to match those defined in the Cadstar part
1829 TERMINAL_TO_PINNUM_MAP pinNumMap;
1830
1831 for( auto&& [storedPinNum, termID] : m_symDefTerminalsMap[aSymdefID] )
1832 {
1833 PART::DEFINITION::PIN csPin = getPartDefinitionPin( aCadstarPart, aGateID, termID );
1834 std::vector<SCH_PIN*> pins = kiSymDef->GetPinsByNumber( storedPinNum );
1835
1836 wxString pinName = HandleTextOverbar( csPin.Label );
1837 wxString pinNum = HandleTextOverbar( csPin.Name );
1838
1839 if( pinNum.IsEmpty() )
1840 {
1841 if( !csPin.Identifier.IsEmpty() )
1842 pinNum = csPin.Identifier;
1843 else if( csPin.ID == UNDEFINED_VALUE )
1844 pinNum = wxString::Format( "%ld", termID );
1845 else
1846 pinNum = wxString::Format( "%ld", csPin.ID );
1847 }
1848
1849 for( SCH_PIN* pin : pins )
1850 {
1851 pin->SetType( getKiCadPinType( csPin.Type ) );
1852 pin->SetNumber( pinNum );
1853 pin->SetName( pinName );
1854 }
1855
1856 pinNumMap.insert( { termID, pinNum } );
1857 }
1858
1859 m_pinNumsMap.insert( { aCadstarPart.ID + aGateID, pinNumMap } );
1860
1861 // COPY ITEMS
1862 int gateNumber = getKiCadUnitNumberFromGate( aGateID );
1863 copySymbolItems( kiSymDef.get(), aSymbol, gateNumber );
1864
1865 // Hide the value field for now (it might get unhidden if an attribute exists in the cadstar
1866 // design with the text "Value"
1867 aSymbol->GetValueField().SetVisible( false );
1868
1869
1870 if( SCH_FIELD* partNameField = aSymbol->GetField( PartNameFieldName ) )
1871 partNameField->SetText( EscapeFieldText( aCadstarPart.Name ) );
1872
1873 const POINT& symDefOrigin = Library.SymbolDefinitions.at( aSymdefID ).Origin;
1874 wxString footprintRefName = wxEmptyString;
1875 wxString footprintAlternateName = wxEmptyString;
1876
1877 auto loadLibraryField = [&]( const ATTRIBUTE_VALUE& aAttributeVal )
1878 {
1879 wxString attrName = getAttributeName( aAttributeVal.AttributeID );
1880
1881 // Remove invalid field characters
1882 wxString attributeValue = aAttributeVal.Value;
1883 attributeValue.Replace( wxT( "\n" ), wxT( "\\n" ) );
1884 attributeValue.Replace( wxT( "\r" ), wxT( "\\r" ) );
1885 attributeValue.Replace( wxT( "\t" ), wxT( "\\t" ) );
1886
1887 //TODO: Handle "links": In cadstar a field can be a "link" if its name starts
1888 // with the characters "Link ". Need to figure out how to convert them to
1889 // equivalent in KiCad.
1890
1891 if( attrName == wxT( "(PartDefinitionNameStem)" ) )
1892 {
1893 //Space not allowed in Reference field
1894 attributeValue.Replace( wxT( " " ), "_" );
1895 aSymbol->GetReferenceField().SetText( attributeValue );
1896 return;
1897 }
1898 else if( attrName == wxT( "(PartDescription)" ) )
1899 {
1900 aSymbol->SetDescription( attributeValue );
1901 return;
1902 }
1903 else if( attrName == wxT( "(PartDefinitionReferenceName)" ) )
1904 {
1905 footprintRefName = attributeValue;
1906 return;
1907 }
1908 else if( attrName == wxT( "(PartDefinitionAlternateName)" ) )
1909 {
1910 footprintAlternateName = attributeValue;
1911 return;
1912 }
1913
1914 bool attrIsNew = aSymbol->GetField( attrName ) == nullptr;
1915 SCH_FIELD* attrField = addNewFieldToSymbol( attrName, aSymbol );
1916
1917 wxASSERT( attrField->GetName() == attrName );
1918 attrField->SetText( attributeValue );
1919 attrField->SetUnit( gateNumber );
1920
1921 const ATTRIBUTE_ID& attrid = aAttributeVal.AttributeID;
1922 attrField->SetVisible( isAttributeVisible( attrid ) );
1923
1924 if( aAttributeVal.HasLocation )
1925 {
1926 // Check if the part itself defined a location for the field
1927 applyToLibraryFieldAttribute( aAttributeVal.AttributeLocation, symDefOrigin, attrField );
1928 }
1929 else if( attrIsNew )
1930 {
1931 attrField->SetVisible( false );
1932 applyTextSettings( attrField, wxT( "TC1" ), ALIGNMENT::NO_ALIGNMENT, JUSTIFICATION::LEFT, false, true );
1933 }
1934 };
1935
1936 // Load all attributes in the Part Definition
1937 for( auto& [attrId, attrVal] : aCadstarPart.Definition.AttributeValues )
1938 loadLibraryField( attrVal );
1939
1940 // Load all attributes in the Part itself.
1941 for( auto& [attrId, attrVal] : aCadstarPart.AttributeValues )
1942 loadLibraryField( attrVal );
1943
1944 setFootprintOnSymbol( aSymbol, footprintRefName, footprintAlternateName );
1945
1946 if( aCadstarPart.Definition.HidePinNames )
1947 {
1948 aSymbol->SetShowPinNames( false );
1949 aSymbol->SetShowPinNumbers( false );
1950 }
1951}
1952
1953
1955 const wxString& aFootprintName,
1956 const wxString& aFootprintAlternate )
1957{
1958 wxString fpNameInLibrary = generateLibName( aFootprintName, aFootprintAlternate );
1959
1960 if( !fpNameInLibrary.IsEmpty() )
1961 {
1962 wxArrayString fpFilters;
1963 fpFilters.Add( aFootprintName ); // In cadstar one footprint has several "alternates"
1964
1965 if( !aFootprintAlternate.IsEmpty() )
1966 fpFilters.Add( fpNameInLibrary );
1967
1968 aKiCadSymbol->SetFPFilters( fpFilters );
1969
1970 LIB_ID libID( m_footprintLibName, fpNameInLibrary );
1971 aKiCadSymbol->GetFootprintField().SetText( libID.Format() );
1972 }
1973}
1974
1975
1976void CADSTAR_SCH_ARCHIVE_LOADER::loadLibrarySymbolShapeVertices( const std::vector<VERTEX>& aCadstarVertices,
1977 const VECTOR2I& aSymbolOrigin,
1978 LIB_SYMBOL* aSymbol, int aGateNumber,
1979 int aLineThickness, LINE_STYLE aLineStyle )
1980{
1981 const VERTEX* prev = aCadstarVertices.empty() ? nullptr : &aCadstarVertices.at( 0 );
1982 const VERTEX* cur;
1983
1984 wxASSERT_MSG( prev->Type == VERTEX_TYPE::VT_POINT, "First vertex should always be a point." );
1985
1986 for( size_t i = 1; i < aCadstarVertices.size(); i++ )
1987 {
1988 cur = &aCadstarVertices.at( i );
1989
1990 SCH_SHAPE* shape = nullptr;
1991 bool cw = false;
1992 VECTOR2I startPoint = getKiCadLibraryPoint( prev->End, aSymbolOrigin );
1993 VECTOR2I endPoint = getKiCadLibraryPoint( cur->End, aSymbolOrigin );
1994 VECTOR2I centerPoint;
1995
1997 centerPoint = ( startPoint + endPoint ) / 2;
1998 else
1999 centerPoint = getKiCadLibraryPoint( cur->Center, aSymbolOrigin );
2000
2001 switch( cur->Type )
2002 {
2004 shape = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2005 shape->AddPoint( startPoint );
2006 shape->AddPoint( endPoint );
2007 break;
2008
2011 cw = true;
2013
2016 shape = new SCH_SHAPE( SHAPE_T::ARC, LAYER_DEVICE );
2017
2018 shape->SetPosition( centerPoint );
2019
2020 if( cw )
2021 {
2022 shape->SetStart( endPoint );
2023 shape->SetEnd( startPoint );
2024 }
2025 else
2026 {
2027 shape->SetStart( startPoint );
2028 shape->SetEnd( endPoint );
2029 }
2030
2031 break;
2032 }
2033
2034 shape->SetUnit( aGateNumber );
2035 shape->SetStroke( STROKE_PARAMS( aLineThickness, aLineStyle ) );
2036 aSymbol->AddDrawItem( shape, false );
2037
2038 prev = cur;
2039 }
2040
2041 aSymbol->GetDrawItems().sort();
2042}
2043
2044
2046 const VECTOR2I& aSymbolOrigin,
2047 SCH_FIELD* aKiCadField )
2048{
2049 aKiCadField->SetTextPos( getKiCadLibraryPoint( aCadstarAttrLoc.Position, aSymbolOrigin ) );
2050
2051 applyTextSettings( aKiCadField, aCadstarAttrLoc.TextCodeID, aCadstarAttrLoc.Alignment,
2052 aCadstarAttrLoc.Justification, aCadstarAttrLoc.OrientAngle,
2053 aCadstarAttrLoc.Mirror );
2054}
2055
2056
2058 const LIB_SYMBOL& aKiCadPart,
2059 EDA_ANGLE& aComponentOrientation )
2060{
2061 wxString libName = CreateLibName( m_footprintLibName, m_rootSheet );
2062
2063 LIB_ID libId;
2064 libId.SetLibItemName( aKiCadPart.GetName() );
2065 libId.SetLibNickname( libName );
2066
2067 int unit = getKiCadUnitNumberFromGate( aCadstarSymbol.GateID );
2068
2069 if( m_sheetMap.find( aCadstarSymbol.LayerID ) == m_sheetMap.end() )
2070 {
2071 m_reporter->Report( wxString::Format( _( "Symbol '%s' references sheet ID '%s' which does not exist "
2072 "in the design. The symbol was not loaded." ),
2073 aCadstarSymbol.ComponentRef.Designator,
2074 aCadstarSymbol.LayerID ),
2076
2077 return nullptr;
2078 }
2079
2080 SCH_SHEET_PATH sheetpath;
2081 SCH_SHEET* kiSheet = m_sheetMap.at( aCadstarSymbol.LayerID );
2082 m_rootSheet->LocatePathOfScreen( kiSheet->GetScreen(), &sheetpath );
2083
2084 SCH_SYMBOL* symbol = new SCH_SYMBOL( aKiCadPart, libId, &sheetpath, unit );
2085
2086 if( aCadstarSymbol.IsComponent )
2087 symbol->SetRef( &sheetpath, aCadstarSymbol.ComponentRef.Designator );
2088
2089 symbol->SetPosition( getKiCadPoint( aCadstarSymbol.Origin ) );
2090
2091 EDA_ANGLE compAngle = getAngle( aCadstarSymbol.OrientAngle );
2092 int compOrientation = 0;
2093
2094 if( aCadstarSymbol.Mirror )
2095 {
2096 compAngle = -compAngle;
2097 compOrientation += SYMBOL_ORIENTATION_T::SYM_MIRROR_Y;
2098 }
2099
2100 compOrientation += getComponentOrientation( compAngle, aComponentOrientation );
2101 EDA_ANGLE test1( compAngle );
2102 EDA_ANGLE test2( aComponentOrientation );
2103
2104 if( test1.Normalize180() != test2.Normalize180() )
2105 {
2106 m_reporter->Report( wxString::Format( _( "Symbol '%s' is rotated by an angle of %.1f " //format:allow
2107 "degrees in the original CADSTAR design but "
2108 "KiCad only supports rotation angles multiples "
2109 "of 90 degrees. The connecting wires will need "
2110 "manual fixing." ),
2111 aCadstarSymbol.ComponentRef.Designator,
2112 compAngle.AsDegrees() ),
2114 }
2115
2116 symbol->SetOrientation( compOrientation );
2117
2118 wxString gate = ( aCadstarSymbol.GateID.IsEmpty() ) ? wxString( wxT( "A" ) ) : aCadstarSymbol.GateID;
2119 wxString partGateIndex = aCadstarSymbol.PartRef.RefID + gate;
2120
2121 //Handle pin swaps
2122 if( m_pinNumsMap.find( partGateIndex ) != m_pinNumsMap.end() )
2123 {
2124 TERMINAL_TO_PINNUM_MAP termNumMap = m_pinNumsMap.at( partGateIndex );
2125
2126 std::map<wxString, std::vector<SCH_PIN*>> pinNumToLibPinsMap;
2127
2128 for( auto& term : termNumMap )
2129 {
2130 wxString pinNum = term.second;
2131 std::vector<SCH_PIN*> pins =
2132 symbol->GetLibSymbolRef()->GetPinsByNumber( term.second );
2133 pinNumToLibPinsMap.insert( { pinNum, pins } );
2134 }
2135
2136 auto replacePinNumber =
2137 [&]( const wxString& aOldPinNum, const wxString& aNewPinNum )
2138 {
2139 if( aOldPinNum == aNewPinNum )
2140 return;
2141
2142 for( SCH_PIN* libpin : pinNumToLibPinsMap.at( aOldPinNum ) )
2143 libpin->SetNumber( HandleTextOverbar( aNewPinNum ) );
2144 };
2145
2146 //Older versions of Cadstar used pin numbers
2147 for( auto& pinPair : aCadstarSymbol.PinNumbers )
2148 {
2149 SYMBOL::PIN_NUM pin = pinPair.second;
2150
2151 replacePinNumber( termNumMap.at( pin.TerminalID ),
2152 wxString::Format( "%ld", pin.PinNum ) );
2153 }
2154
2155 //Newer versions of Cadstar use pin names
2156 for( auto& pinPair : aCadstarSymbol.PinNames )
2157 {
2158 SYMPINNAME_LABEL pin = pinPair.second;
2159 replacePinNumber( termNumMap.at( pin.TerminalID ), pin.NameOrLabel );
2160 }
2161
2162 symbol->UpdatePins();
2163 }
2164
2165 kiSheet->GetScreen()->Append( symbol );
2166
2167 return symbol;
2168}
2169
2170
2172 const EDA_ANGLE& aComponentOrientation,
2173 bool aIsMirrored,
2174 SCH_FIELD* aKiCadField )
2175{
2176 aKiCadField->SetPosition( getKiCadPoint( aCadstarAttrLoc.Position ) );
2177 aKiCadField->SetVisible( true );
2178
2179 ALIGNMENT alignment = aCadstarAttrLoc.Alignment;
2180 EDA_ANGLE textAngle = getAngle( aCadstarAttrLoc.OrientAngle );
2181
2182 if( aIsMirrored )
2183 {
2184 // We need to change the aligment when the symbol is mirrored based on the text orientation
2185 // To ensure the anchor point is the same in KiCad.
2186
2187 int textIsVertical = KiROUND( textAngle.AsDegrees() / 90.0 ) % 2;
2188
2189 if( textIsVertical )
2190 alignment = rotate180( alignment );
2191
2192 alignment = mirrorX( alignment );
2193 }
2194
2195 applyTextSettings( aKiCadField, aCadstarAttrLoc.TextCodeID, alignment,
2196 aCadstarAttrLoc.Justification,
2197 getCadstarAngle( textAngle - aComponentOrientation ),
2198 aCadstarAttrLoc.Mirror );
2199}
2200
2201
2203 EDA_ANGLE& aReturnedOrientation )
2204{
2205 int compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_0;
2206
2207 EDA_ANGLE oDeg = aOrientAngle;
2208 oDeg.Normalize180();
2209
2210 if( oDeg >= -ANGLE_45 && oDeg <= ANGLE_45 )
2211 {
2212 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_0;
2213 aReturnedOrientation = ANGLE_0;
2214 }
2215 else if( oDeg >= ANGLE_45 && oDeg <= ANGLE_135 )
2216 {
2217 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_90;
2218 aReturnedOrientation = ANGLE_90;
2219 }
2220 else if( oDeg >= ANGLE_135 || oDeg <= -ANGLE_135 )
2221 {
2222 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_180;
2223 aReturnedOrientation = ANGLE_180;
2224 }
2225 else
2226 {
2227 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_270;
2228 aReturnedOrientation = ANGLE_270;
2229 }
2230
2231 return compOrientation;
2232}
2233
2234
2237{
2238 auto logUnknownNetElementError =
2239 [&]()
2240 {
2241 m_reporter->Report( wxString::Format( _( "Net %s references unknown net element %s. The net was "
2242 "not properly loaded and may require manual fixing." ),
2243 getNetName( aNet ),
2244 aNetElementID ),
2246
2247 return POINT();
2248 };
2249
2250 if( aNetElementID.Contains( "J" ) ) // Junction
2251 {
2252 if( aNet.Junctions.find( aNetElementID ) == aNet.Junctions.end() )
2253 return logUnknownNetElementError();
2254
2255 return aNet.Junctions.at( aNetElementID ).Location;
2256 }
2257 else if( aNetElementID.Contains( "P" ) ) // Terminal/Pin of a symbol
2258 {
2259 if( aNet.Terminals.find( aNetElementID ) == aNet.Terminals.end() )
2260 return logUnknownNetElementError();
2261
2262 SYMBOL_ID symid = aNet.Terminals.at( aNetElementID ).SymbolID;
2263 TERMINAL_ID termid = aNet.Terminals.at( aNetElementID ).TerminalID;
2264
2265 if( Schematic.Symbols.find( symid ) == Schematic.Symbols.end() )
2266 return logUnknownNetElementError();
2267
2268 SYMBOL sym = Schematic.Symbols.at( symid );
2269 SYMDEF_ID symdefid = sym.SymdefID;
2270 VECTOR2I symbolOrigin( sym.Origin.x, sym.Origin.y );
2271
2272 if( Library.SymbolDefinitions.find( symdefid ) == Library.SymbolDefinitions.end() )
2273 return logUnknownNetElementError();
2274
2275 const SYMDEF_SCM symdef = Library.SymbolDefinitions.at( symdefid );
2276 VECTOR2I libOrigin( symdef.Origin.x, symdef.Origin.y );
2277
2278 if( symdef.Terminals.find( termid ) == symdef.Terminals.end() )
2279 {
2280 m_reporter->Report( wxString::Format( _( "Net %s references unknown terminal %s on symbol %s. "
2281 "The net was not properly loaded and may require manual "
2282 "fixing." ),
2283 getNetName( aNet ),
2284 termid,
2285 symdefid ),
2287
2288 return POINT();
2289 }
2290
2291 TERMINAL term = symdef.Terminals.at( termid );
2292 VECTOR2I libpinPosition( term.Position.x, term.Position.y );
2293
2294 VECTOR2I pinOffset = libpinPosition - libOrigin;
2295 pinOffset.x = ( pinOffset.x * sym.ScaleRatioNumerator ) / sym.ScaleRatioDenominator;
2296 pinOffset.y = ( pinOffset.y * sym.ScaleRatioNumerator ) / sym.ScaleRatioDenominator;
2297
2298 VECTOR2I pinPosition = symbolOrigin + pinOffset;
2299 EDA_ANGLE compAngle = getAngle( sym.OrientAngle );
2300
2301 if( sym.Mirror )
2302 pinPosition.x = ( 2 * symbolOrigin.x ) - pinPosition.x;
2303
2304 EDA_ANGLE adjustedOrientation;
2305 getComponentOrientation( compAngle, adjustedOrientation );
2306
2307 RotatePoint( pinPosition, symbolOrigin, -adjustedOrientation );
2308
2309 POINT retval;
2310 retval.x = pinPosition.x;
2311 retval.y = pinPosition.y;
2312
2313 return retval;
2314 }
2315 else if( aNetElementID.Contains( "BT" ) ) // Bus Terminal
2316 {
2317 if( aNet.BusTerminals.find( aNetElementID ) == aNet.BusTerminals.end() )
2318 return logUnknownNetElementError();
2319
2320 return aNet.BusTerminals.at( aNetElementID ).SecondPoint;
2321 }
2322 else if( aNetElementID.Contains( "BLKT" ) ) // Block Terminal (sheet hierarchy connection)
2323 {
2324 if( aNet.BlockTerminals.find( aNetElementID ) == aNet.BlockTerminals.end() )
2325 return logUnknownNetElementError();
2326
2327 BLOCK_ID blockid = aNet.BlockTerminals.at( aNetElementID ).BlockID;
2328 TERMINAL_ID termid = aNet.BlockTerminals.at( aNetElementID ).TerminalID;
2329
2330 if( Schematic.Blocks.find( blockid ) == Schematic.Blocks.end() )
2331 return logUnknownNetElementError();
2332
2333 BLOCK block = Schematic.Blocks.at( blockid );
2334
2335 if( block.Terminals.find( termid ) == block.Terminals.end() )
2336 {
2337 m_reporter->Report( wxString::Format( _( "Net %s references unknown terminal %s on block %s. The net "
2338 "was not properly loaded and may require manual fixing." ),
2339 getNetName( aNet ),
2340 termid,
2341 blockid ),
2343
2344 return POINT();
2345 }
2346
2347 return block.Terminals.at( termid ).Position;
2348 }
2349 else if( aNetElementID.Contains( "D" ) ) // Dangler
2350 {
2351 if( aNet.Danglers.find( aNetElementID ) == aNet.Danglers.end() )
2352 return logUnknownNetElementError();
2353
2354 return aNet.Danglers.at( aNetElementID ).Position;
2355 }
2356 else
2357 {
2358 return logUnknownNetElementError();
2359 }
2360}
2361
2362
2364{
2365 wxString netname = aNet.Name;
2366
2367 if( netname.IsEmpty() )
2368 netname = wxString::Format( "$%ld", aNet.SignalNum );
2369
2370 return netname;
2371}
2372
2373
2374void CADSTAR_SCH_ARCHIVE_LOADER::loadShapeVertices( const std::vector<VERTEX>& aCadstarVertices,
2375 LINECODE_ID aCadstarLineCodeID,
2376 LAYER_ID aCadstarSheetID,
2377 SCH_LAYER_ID aKiCadSchLayerID,
2378 const VECTOR2I& aMoveVector,
2379 const EDA_ANGLE& aRotation,
2380 const double& aScalingFactor,
2381 const VECTOR2I& aTransformCentre,
2382 const bool& aMirrorInvert )
2383{
2384 int lineWidth = KiROUND( getLineThickness( aCadstarLineCodeID ) * aScalingFactor );
2385 LINE_STYLE lineStyle = getLineStyle( aCadstarLineCodeID );
2386
2387 const VERTEX* prev = aCadstarVertices.empty() ? nullptr : &aCadstarVertices.at( 0 );
2388 const VERTEX* cur;
2389
2390 wxASSERT_MSG( prev->Type == VERTEX_TYPE::VT_POINT, "First vertex should always be a point vertex" );
2391
2392 auto pointTransform =
2393 [&]( const VECTOR2I& aV )
2394 {
2395 return applyTransform( getKiCadPoint( aV ), aMoveVector, aRotation,
2396 aScalingFactor, aTransformCentre, aMirrorInvert );
2397 };
2398
2399 for( size_t ii = 1; ii < aCadstarVertices.size(); ii++ )
2400 {
2401 cur = &aCadstarVertices.at( ii );
2402
2403 VECTOR2I transformedStartPoint = pointTransform( prev->End );
2404 VECTOR2I transformedEndPoint = pointTransform( cur->End );
2405
2406 switch( cur->Type )
2407 {
2412 {
2413 SHAPE_ARC tempArc = cur->BuildArc( transformedStartPoint, pointTransform );
2414
2415 SCH_SHAPE* arcShape = new SCH_SHAPE( SHAPE_T::ARC, LAYER_NOTES, lineWidth );
2416 arcShape->SetArcGeometry( tempArc.GetP0(), tempArc.GetArcMid(), tempArc.GetP1() );
2417 arcShape->SetLineStyle( lineStyle );
2418
2419 loadItemOntoKiCadSheet( aCadstarSheetID, arcShape );
2420 break;
2421 }
2422
2424 {
2425 SCH_LINE* segment = new SCH_LINE();
2426
2427 segment->SetLayer( aKiCadSchLayerID );
2428 segment->SetLineWidth( lineWidth );
2429 segment->SetLineStyle( lineStyle );
2430
2431 segment->SetStartPoint( transformedStartPoint );
2432 segment->SetEndPoint( transformedEndPoint );
2433
2434 loadItemOntoKiCadSheet( aCadstarSheetID, segment );
2435 break;
2436 }
2437
2438 default:
2439 wxFAIL_MSG( "Unknown CADSTAR Vertex type" );
2440 }
2441
2442 prev = cur;
2443 }
2444}
2445
2446
2448 const LAYER_ID& aCadstarSheetIDOverride,
2449 SCH_LAYER_ID aKiCadSchLayerID,
2450 const VECTOR2I& aMoveVector,
2451 const EDA_ANGLE& aRotation,
2452 const double& aScalingFactor,
2453 const VECTOR2I& aTransformCentre,
2454 const bool& aMirrorInvert )
2455{
2456 loadShapeVertices( aCadstarFigure.Shape.Vertices, aCadstarFigure.LineCodeID,
2457 aCadstarSheetIDOverride, aKiCadSchLayerID, aMoveVector, aRotation,
2458 aScalingFactor, aTransformCentre, aMirrorInvert );
2459
2460 for( const CUTOUT& cutout : aCadstarFigure.Shape.Cutouts )
2461 {
2462 loadShapeVertices( cutout.Vertices, aCadstarFigure.LineCodeID, aCadstarSheetIDOverride,
2463 aKiCadSchLayerID, aMoveVector, aRotation, aScalingFactor,
2464 aTransformCentre, aMirrorInvert );
2465 }
2466}
2467
2468
2470 const VECTOR2I& aPosition,
2471 const VECTOR2I& aSheetSize,
2472 const SCH_SHEET_PATH& aParentSheet )
2473{
2474 wxCHECK_MSG( m_sheetMap.find( aCadstarSheetID ) == m_sheetMap.end(), ,
2475 "Sheet already loaded!" );
2476
2477 SCH_SHEET* sheet = new SCH_SHEET(
2478 /* aParent */ aParentSheet.Last(),
2479 /* aPosition */ aPosition,
2480 /* aSize */ VECTOR2I( aSheetSize ) );
2481 SCH_SCREEN* screen = new SCH_SCREEN( m_schematic );
2482 SCH_SHEET_PATH instance( aParentSheet );
2483
2484 sheet->SetScreen( screen );
2485
2486 wxString name = Sheets.SheetNames.at( aCadstarSheetID );
2487
2489
2490 int sheetNum = getSheetNumber( aCadstarSheetID );
2491 wxString loadedFilename = wxFileName( Filename ).GetName();
2492 std::string filename = wxString::Format( "%s_%02d", loadedFilename, sheetNum ).ToStdString();
2493
2494 ReplaceIllegalFileNameChars( filename );
2495 filename += wxT( "." ) + wxString( FILEEXT::KiCadSchematicFileExtension );
2496
2497 sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( filename );
2498
2499 wxFileName fn( m_schematic->Project().GetProjectPath() + filename );
2500 sheet->GetScreen()->SetFileName( fn.GetFullPath() );
2501 aParentSheet.Last()->GetScreen()->Append( sheet );
2502 instance.push_back( sheet );
2503
2504 wxString pageNumStr = wxString::Format( "%d", getSheetNumber( aCadstarSheetID ) );
2505 instance.SetPageNumber( pageNumStr );
2506
2507 sheet->AutoplaceFields( nullptr, AUTOPLACE_AUTO );
2508
2509 m_sheetMap.insert( { aCadstarSheetID, sheet } );
2510
2511 loadChildSheets( aCadstarSheetID, instance );
2512}
2513
2514
2516 const SCH_SHEET_PATH& aSheet )
2517{
2518 wxCHECK_MSG( m_sheetMap.find( aCadstarSheetID ) != m_sheetMap.end(), ,
2519 "FIXME! Parent sheet should be loaded before attempting to load subsheets" );
2520
2521 for( std::pair<BLOCK_ID, BLOCK> blockPair : Schematic.Blocks )
2522 {
2523 BLOCK& block = blockPair.second;
2524
2525 if( block.LayerID == aCadstarSheetID && block.Type == BLOCK::TYPE::CHILD )
2526 {
2527 if( block.AssocLayerID == wxT( "NO_LINK" ) )
2528 {
2529 if( block.Figures.size() > 0 )
2530 {
2531 m_reporter->Report( wxString::Format( _( "The block ID %s (Block name: '%s') is drawn on sheet "
2532 "'%s' but is not linked to another sheet in the design. "
2533 "KiCad requires all sheet symbols to be associated to a "
2534 "sheet, so the block was not loaded." ),
2535 block.ID, block.Name,
2536 Sheets.SheetNames.at( aCadstarSheetID ) ),
2538 }
2539
2540 continue;
2541 }
2542
2543 // In KiCad you can only draw rectangular shapes whereas in Cadstar arbitrary shapes
2544 // are allowed. We will calculate the extents of the Cadstar shape and draw a rectangle
2545
2546 std::pair<VECTOR2I, VECTOR2I> blockExtents;
2547
2548 if( block.Figures.size() > 0 )
2549 {
2550 blockExtents = getFigureExtentsKiCad( block.Figures.begin()->second );
2551 }
2552 else
2553 {
2554 THROW_IO_ERROR( wxString::Format( _( "The CADSTAR schematic might be corrupt: Block %s references "
2555 "a child sheet but has no Figure defined." ),
2556 block.ID ) );
2557 }
2558
2559 loadSheetAndChildSheets( block.AssocLayerID, blockExtents.first, blockExtents.second,
2560 aSheet );
2561
2562 // Hide all KiCad sheet properties (sheet name/filename is not applicable in CADSTAR)
2563 SCH_SHEET* loadedSheet = m_sheetMap.at( block.AssocLayerID );
2564 std::vector<SCH_FIELD> fields = loadedSheet->GetFields();
2565
2566 for( SCH_FIELD& field : fields )
2567 {
2568 field.SetVisible( false );
2569 }
2570
2571 if( block.HasBlockLabel )
2572 {
2573 //@todo use below code when KiCad supports multi-line fields
2574 /*
2575 // Add the block label as a separate field
2576 SCH_FIELD blockNameField( getKiCadPoint( block.BlockLabel.Position ), 2,
2577 loadedSheet, wxString( "Block name" ) );
2578 blockNameField.SetText( block.Name );
2579 blockNameField.SetVisible( true );
2580
2581 applyTextSettings( &blockNameField,
2582 block.BlockLabel.TextCodeID,
2583 block.BlockLabel.Alignment,
2584 block.BlockLabel.Justification,
2585 block.BlockLabel.OrientAngle,
2586 block.BlockLabel.Mirror );
2587
2588 fields.push_back( blockNameField );*/
2589
2590 // For now as as a text item (supports multi-line properly)
2591 SCH_TEXT* kiTxt = new SCH_TEXT();
2592
2593 kiTxt->SetParent( m_schematic );
2594 kiTxt->SetPosition( getKiCadPoint( block.BlockLabel.Position ) );
2595 kiTxt->SetText( block.Name );
2596
2599 block.BlockLabel.Mirror );
2600
2601 loadItemOntoKiCadSheet( aCadstarSheetID, kiTxt );
2602 }
2603
2604 loadedSheet->SetFields( fields );
2605 }
2606 }
2607}
2608
2609
2610std::vector<CADSTAR_SCH_ARCHIVE_LOADER::LAYER_ID> CADSTAR_SCH_ARCHIVE_LOADER::findOrphanSheets()
2611{
2612 std::vector<LAYER_ID> childSheets, orphanSheets;
2613
2614 //Find all sheets that are child of another
2615 for( std::pair<BLOCK_ID, BLOCK> blockPair : Schematic.Blocks )
2616 {
2617 BLOCK& block = blockPair.second;
2618 LAYER_ID& assocSheetID = block.AssocLayerID;
2619
2620 if( block.Type == BLOCK::TYPE::CHILD )
2621 childSheets.push_back( assocSheetID );
2622 }
2623
2624 //Add sheets that do not have a parent
2625 for( const LAYER_ID& sheetID : Sheets.SheetOrder )
2626 {
2627 if( std::find( childSheets.begin(), childSheets.end(), sheetID ) == childSheets.end() )
2628 orphanSheets.push_back( sheetID );
2629 }
2630
2631 return orphanSheets;
2632}
2633
2634
2636{
2637 int i = 1;
2638
2639 for( const LAYER_ID& sheetID : Sheets.SheetOrder )
2640 {
2641 if( sheetID == aCadstarSheetID )
2642 return i;
2643
2644 ++i;
2645 }
2646
2647 return -1;
2648}
2649
2650
2652 SCH_ITEM* aItem )
2653{
2654 wxCHECK_MSG( aItem, /*void*/, wxT( "aItem is null" ) );
2655
2656 if( aCadstarSheetID == "ALL_SHEETS" )
2657 {
2658 for( std::pair<LAYER_ID, SHEET_NAME> sheetPair : Sheets.SheetNames )
2659 {
2660 LAYER_ID sheetID = sheetPair.first;
2661 m_sheetMap.at( sheetID )->GetScreen()->Append( aItem->Duplicate( IGNORE_PARENT_GROUP ) );
2662 }
2663
2664 delete aItem;
2665 }
2666 else if( aCadstarSheetID == "NO_SHEET" )
2667 {
2668 wxFAIL_MSG( wxT( "Trying to add an item to NO_SHEET? This might be a documentation symbol." ) );
2669 }
2670 else
2671 {
2672 if( m_sheetMap.find( aCadstarSheetID ) != m_sheetMap.end() )
2673 {
2674 m_sheetMap.at( aCadstarSheetID )->GetScreen()->Append( aItem );
2675 }
2676 else
2677 {
2678 delete aItem;
2679 wxFAIL_MSG( wxT( "Unknown Sheet ID." ) );
2680 }
2681 }
2682}
2683
2684
2687 const wxString& aSymDefAlternate )
2688{
2689 if( m_SymDefNamesCache.size() != Library.SymbolDefinitions.size() )
2690 {
2691 // Re-initialise
2692 m_SymDefNamesCache.clear();
2694
2695 // Create a lower case cache to avoid searching each time
2696 for( auto& [id, symdef] : Library.SymbolDefinitions )
2697 {
2698 wxString refKey = symdef.ReferenceName.Lower();
2699 wxString altKey = symdef.Alternate.Lower();
2700
2701 m_SymDefNamesCache[{ refKey, altKey }] = id;
2702
2703 // Secondary cache to find symbols just by the Name (e.g. if the alternate
2704 // does not exist, we still want to return a symbo - the same behaviour
2705 // as CADSTAR
2706
2707 if( !m_DefaultSymDefNamesCache.count( refKey ) )
2708 {
2709 m_DefaultSymDefNamesCache.insert( { refKey, id } );
2710 }
2711 else if( altKey.IsEmpty() )
2712 {
2713 // Always use the empty alternate if it exists
2714 m_DefaultSymDefNamesCache[refKey] = id;
2715 }
2716 }
2717 }
2718
2719 wxString refKeyToFind = aSymdefName.Lower();
2720 wxString altKeyToFind = aSymDefAlternate.Lower();
2721
2722 if( m_SymDefNamesCache.count( { refKeyToFind, altKeyToFind } ) )
2723 {
2724 return m_SymDefNamesCache[{ refKeyToFind, altKeyToFind }];
2725 }
2726 else if( m_DefaultSymDefNamesCache.count( refKeyToFind ) )
2727 {
2728 return m_DefaultSymDefNamesCache[refKeyToFind];
2729 }
2730
2731 return SYMDEF_ID();
2732}
2733
2734
2736{
2737 // Use CADSTAR visibility settings to determine if an attribute is visible
2738 if( AttrColors.AttributeColors.find( aCadstarAttributeID ) != AttrColors.AttributeColors.end() )
2739 return AttrColors.AttributeColors.at( aCadstarAttributeID ).IsVisible;
2740
2741 return false; // If there is no visibility setting, assume not displayed
2742}
2743
2744
2746{
2747 wxCHECK( Assignments.Codedefs.LineCodes.find( aCadstarLineCodeID ) != Assignments.Codedefs.LineCodes.end(),
2748 schIUScale.MilsToIU( DEFAULT_WIRE_WIDTH_MILS ) );
2749
2750 return getKiCadLength( Assignments.Codedefs.LineCodes.at( aCadstarLineCodeID ).Width );
2751}
2752
2753
2755{
2756 wxCHECK( Assignments.Codedefs.LineCodes.find( aCadstarLineCodeID ) != Assignments.Codedefs.LineCodes.end(),
2758
2759 switch( Assignments.Codedefs.LineCodes.at( aCadstarLineCodeID ).Style )
2760 {
2761 case LINESTYLE::DASH: return LINE_STYLE::DASH;
2764 case LINESTYLE::DOT: return LINE_STYLE::DOT;
2766 default: return LINE_STYLE::DEFAULT;
2767 }
2768}
2769
2770
2773{
2774 wxCHECK( Assignments.Codedefs.TextCodes.find( aCadstarTextCodeID ) != Assignments.Codedefs.TextCodes.end(),
2775 TEXTCODE() );
2776
2777 return Assignments.Codedefs.TextCodes.at( aCadstarTextCodeID );
2778}
2779
2780
2782{
2783 TEXTCODE txtCode = getTextCode( aCadstarTextCodeID );
2784
2785 return KiROUND( (double) getKiCadLength( txtCode.Height ) * TXT_HEIGHT_RATIO );
2786}
2787
2788
2790{
2791 wxCHECK( Assignments.Codedefs.AttributeNames.find( aCadstarAttributeID )
2792 != Assignments.Codedefs.AttributeNames.end(),
2793 aCadstarAttributeID );
2794
2795 return Assignments.Codedefs.AttributeNames.at( aCadstarAttributeID ).Name;
2796}
2797
2798
2801{
2802 wxCHECK( Parts.PartDefinitions.find( aCadstarPartID ) != Parts.PartDefinitions.end(), PART() );
2803
2804 return Parts.PartDefinitions.at( aCadstarPartID );
2805}
2806
2807
2810{
2811 wxCHECK( Assignments.Codedefs.RouteCodes.find( aCadstarRouteCodeID ) != Assignments.Codedefs.RouteCodes.end(),
2812 ROUTECODE() );
2813
2814 return Assignments.Codedefs.RouteCodes.at( aCadstarRouteCodeID );
2815}
2816
2817
2818CADSTAR_SCH_ARCHIVE_LOADER::PART::DEFINITION::PIN
2820 const TERMINAL_ID& aTerminalID )
2821{
2822 for( std::pair<PART_DEFINITION_PIN_ID, PART::DEFINITION::PIN> pinPair :
2823 aCadstarPart.Definition.Pins )
2824 {
2825 PART::DEFINITION::PIN partPin = pinPair.second;
2826
2827 if( partPin.TerminalGate == aGateID && partPin.TerminalPin == aTerminalID )
2828 return partPin;
2829 }
2830
2831 return PART::DEFINITION::PIN();
2832}
2833
2834
2853
2855{
2856 if( aCadstarGateID.IsEmpty() )
2857 return 1;
2858
2859 return (int) aCadstarGateID.Upper().GetChar( 0 ) - (int) wxUniChar( 'A' ) + 1;
2860}
2861
2862
2863SPIN_STYLE CADSTAR_SCH_ARCHIVE_LOADER::getSpinStyle( const long long& aCadstarOrientation, bool aMirror )
2864{
2865 EDA_ANGLE orientation = getAngle( aCadstarOrientation );
2866 SPIN_STYLE spinStyle = getSpinStyle( orientation );
2867
2868 if( aMirror )
2869 {
2870 spinStyle = spinStyle.RotateCCW();
2871 spinStyle = spinStyle.RotateCCW();
2872 }
2873
2874 return spinStyle;
2875}
2876
2877
2879{
2880 SPIN_STYLE spinStyle = SPIN_STYLE::LEFT;
2881
2882 EDA_ANGLE oDeg = aOrientation;
2883 oDeg.Normalize180();
2884
2885 if( oDeg >= -ANGLE_45 && oDeg <= ANGLE_45 )
2886 spinStyle = SPIN_STYLE::RIGHT; // 0deg
2887 else if( oDeg >= ANGLE_45 && oDeg <= ANGLE_135 )
2888 spinStyle = SPIN_STYLE::UP; // 90deg
2889 else if( oDeg >= ANGLE_135 || oDeg <= -ANGLE_135 )
2890 spinStyle = SPIN_STYLE::LEFT; // 180deg
2891 else
2892 spinStyle = SPIN_STYLE::BOTTOM; // 270deg
2893
2894 return spinStyle;
2895}
2896
2897
2900{
2901 switch( aCadstarAlignment )
2902 {
2903 // Change left to right:
2908
2909 //Change right to left:
2913
2914 // Center alignment does not mirror:
2917 case ALIGNMENT::TOPCENTER: return aCadstarAlignment;
2918
2919 // Shouldn't be here
2920 default: wxFAIL_MSG( "Unknown Cadstar Alignment" ); return aCadstarAlignment;
2921 }
2922}
2923
2924
2927{
2928 switch( aCadstarAlignment )
2929 {
2940
2941 // Shouldn't be here
2942 default: wxFAIL_MSG( "Unknown Cadstar Alignment" ); return aCadstarAlignment;
2943 }
2944}
2945
2946
2948 const TEXTCODE_ID& aCadstarTextCodeID )
2949{
2950 // Ensure we have no Cadstar overbar characters
2951 wxString escapedText = HandleTextOverbar( aKiCadTextItem->GetText() );
2952 aKiCadTextItem->SetText( escapedText );
2953
2954 if( !Assignments.Codedefs.TextCodes.count( aCadstarTextCodeID ) )
2955 return;
2956
2957 TEXTCODE textCode = getTextCode( aCadstarTextCodeID );
2958 int textHeight = KiROUND( (double) getKiCadLength( textCode.Height ) * TXT_HEIGHT_RATIO );
2959 int textWidth = getKiCadLength( textCode.Width );
2960
2961 // The width is zero for all non-cadstar fonts. Using a width equal to 2/3 the height seems
2962 // to work well for most fonts.
2963 if( textWidth == 0 )
2964 textWidth = getKiCadLength( 2LL * textCode.Height / 3LL );
2965
2966 aKiCadTextItem->SetTextWidth( textWidth );
2967 aKiCadTextItem->SetTextHeight( textHeight );
2968
2969#if 0
2970 // EEschema currently supports only normal vs bold for text thickness.
2971 aKiCadTextItem->SetTextThickness( getKiCadLength( textCode.LineWidth ) );
2972#endif
2973
2974 // Must come after SetTextSize()
2975 aKiCadTextItem->SetBold( textCode.Font.Modifier1 == FONT_BOLD );
2976 aKiCadTextItem->SetItalic( textCode.Font.Italic );
2977}
2978
2979
2981 const TEXTCODE_ID& aCadstarTextCodeID,
2982 const ALIGNMENT& aCadstarAlignment,
2983 const JUSTIFICATION& aCadstarJustification,
2984 const long long aCadstarOrientAngle,
2985 bool aMirrored )
2986{
2987 applyTextCodeIfExists( aKiCadTextItem, aCadstarTextCodeID );
2988 aKiCadTextItem->SetTextAngle( getAngle( aCadstarOrientAngle ) );
2989
2990 // Justification ignored for now as not supported in Eeschema, but leaving this code in
2991 // place for future upgrades.
2992 // TODO update this when Eeschema supports justification independent of anchor position.
2993 ALIGNMENT textAlignment = aCadstarAlignment;
2994
2995 // KiCad mirrors the justification and alignment when the symbol is mirrored but CADSTAR
2996 // specifies it post-mirroring. In contrast, if the text item itself is mirrored (not
2997 // supported in KiCad), CADSTAR specifies the alignment and justification pre-mirroring
2998 if( aMirrored )
2999 textAlignment = mirrorX( aCadstarAlignment );
3000
3001 auto setAlignment =
3002 [&]( EDA_TEXT* aText, ALIGNMENT aAlignment )
3003 {
3004 switch( aAlignment )
3005 {
3006 case ALIGNMENT::NO_ALIGNMENT: // Bottom left of the first line
3007 //No exact KiCad equivalent, so lets move the position of the text
3013 break;
3014
3018 break;
3019
3023 break;
3024
3028 break;
3029
3033 break;
3034
3038 break;
3039
3040 case ALIGNMENT::TOPLEFT:
3043 break;
3044
3048 break;
3049
3053 break;
3054 }
3055 };
3056
3057 SPIN_STYLE spin = getSpinStyle( aCadstarOrientAngle, aMirrored );
3058 EDA_ITEM* textEdaItem = dynamic_cast<EDA_ITEM*>( aKiCadTextItem );
3059 wxCHECK( textEdaItem, /* void */ ); // ensure this is a EDA_ITEM
3060
3061 if( textEdaItem->Type() == SCH_FIELD_T )
3062 {
3063 // Spin style not used. All text justifications are permitted. However, only orientations
3064 // of 0 deg or 90 deg are supported
3065 EDA_ANGLE angle = aKiCadTextItem->GetTextAngle();
3066 angle.Normalize();
3067
3068 int quadrant = KiROUND( angle.AsDegrees() / 90.0 );
3069 quadrant %= 4;
3070
3071 switch( quadrant )
3072 {
3073 case 0:
3074 angle = ANGLE_HORIZONTAL;
3075 break;
3076 case 1:
3077 angle = ANGLE_VERTICAL;
3078 break;
3079 case 2:
3080 angle = ANGLE_HORIZONTAL;
3081 textAlignment = rotate180( textAlignment );
3082 break;
3083 case 3:
3084 angle = ANGLE_VERTICAL;
3085 textAlignment = rotate180( textAlignment );
3086 break;
3087 default:
3088 wxFAIL_MSG( "Unknown Quadrant" );
3089 }
3090
3091 aKiCadTextItem->SetTextAngle( angle );
3092 setAlignment( aKiCadTextItem, textAlignment );
3093 }
3094 else if( textEdaItem->Type() == SCH_TEXT_T )
3095 {
3096 // Note spin style in a SCH_TEXT results in a vertical alignment GR_TEXT_V_ALIGN_BOTTOM
3097 // so need to adjust the location of the text element based on Cadstar's original text
3098 // alignment (anchor position).
3099 setAlignment( aKiCadTextItem, textAlignment );
3100 BOX2I bb = textEdaItem->GetBoundingBox();
3101 int off = static_cast<SCH_TEXT*>( aKiCadTextItem )->GetTextOffset();
3102 VECTOR2I pos;
3103
3104 // Change the anchor point of the text item to make it match the same bounding box
3105 // And correct the error introduced by the text offsetting in KiCad
3106 switch( spin )
3107 {
3108 case SPIN_STYLE::BOTTOM: pos = { bb.GetRight() - off, bb.GetTop() }; break;
3109 case SPIN_STYLE::UP: pos = { bb.GetRight() - off, bb.GetBottom() }; break;
3110 case SPIN_STYLE::LEFT: pos = { bb.GetRight() , bb.GetBottom() + off }; break;
3111 case SPIN_STYLE::RIGHT: pos = { bb.GetLeft() , bb.GetBottom() + off }; break;
3112 default: wxFAIL_MSG( "Unexpected Spin Style" ); break;
3113 }
3114
3115 aKiCadTextItem->SetTextPos( pos );
3116
3117 switch( spin )
3118 {
3119 case SPIN_STYLE::RIGHT: // Horiz Normal Orientation
3120 aKiCadTextItem->SetTextAngle( ANGLE_HORIZONTAL );
3121 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
3122 break;
3123
3124 case SPIN_STYLE::UP: // Vert Orientation UP
3125 aKiCadTextItem->SetTextAngle( ANGLE_VERTICAL );
3126 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
3127 break;
3128
3129 case SPIN_STYLE::LEFT: // Horiz Orientation - Right justified
3130 aKiCadTextItem->SetTextAngle( ANGLE_HORIZONTAL );
3131 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
3132 break;
3133
3134 case SPIN_STYLE::BOTTOM: // Vert Orientation BOTTOM
3135 aKiCadTextItem->SetTextAngle( ANGLE_VERTICAL );
3136 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
3137 break;
3138
3139 default:
3140 wxFAIL_MSG( "Unexpected Spin Style" );
3141 break;
3142 }
3143
3144 aKiCadTextItem->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
3145 }
3146 else if( SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( aKiCadTextItem ) )
3147 {
3148 // We don't want to change position of net labels as that would break connectivity
3149 label->SetSpinStyle( spin );
3150 }
3151 else
3152 {
3153 wxFAIL_MSG( "Unexpected item type" );
3154 }
3155}
3156
3157
3159{
3160 SCH_TEXT* kiTxt = new SCH_TEXT();
3161
3162 kiTxt->SetParent( m_schematic ); // set to the schematic for now to avoid asserts
3163 kiTxt->SetPosition( getKiCadPoint( aCadstarTextElement.Position ) );
3164 kiTxt->SetText( aCadstarTextElement.Text );
3165
3166 applyTextSettings( kiTxt, aCadstarTextElement.TextCodeID, aCadstarTextElement.Alignment,
3167 aCadstarTextElement.Justification, aCadstarTextElement.OrientAngle,
3168 aCadstarTextElement.Mirror );
3169
3170 return kiTxt;
3171}
3172
3173
3175 long long aScalingFactorNumerator,
3176 long long aScalingFactorDenominator )
3177{
3178 LIB_SYMBOL* retval = new LIB_SYMBOL( *aSymbol );
3179
3180 if( aScalingFactorNumerator == aScalingFactorDenominator )
3181 return retval; // 1:1 scale, nothing to do
3182
3183 auto scaleLen =
3184 [&]( int aLength ) -> int
3185 {
3186 return( aLength * aScalingFactorNumerator ) / aScalingFactorDenominator;
3187 };
3188
3189 auto scalePt =
3190 [&]( VECTOR2I aCoord ) -> VECTOR2I
3191 {
3192 return VECTOR2I( scaleLen( aCoord.x ), scaleLen( aCoord.y ) );
3193 };
3194
3195 auto scaleSize =
3196 [&]( VECTOR2I aSize ) -> VECTOR2I
3197 {
3198 return VECTOR2I( scaleLen( aSize.x ), scaleLen( aSize.y ) );
3199 };
3200
3201 LIB_ITEMS_CONTAINER& items = retval->GetDrawItems();
3202
3203 for( SCH_ITEM& item : items )
3204 {
3205 switch( item.Type() )
3206 {
3208 {
3209 SCH_SHAPE& shape = static_cast<SCH_SHAPE&>( item );
3210
3211 if( shape.GetShape() == SHAPE_T::ARC )
3212 {
3213 shape.SetPosition( scalePt( shape.GetPosition() ) );
3214 shape.SetStart( scalePt( shape.GetStart() ) );
3215 shape.SetEnd( scalePt( shape.GetEnd() ) );
3216 }
3217 else if( shape.GetShape() == SHAPE_T::POLY && !shape.GetPolyShape().IsEmpty() )
3218 {
3219 SHAPE_LINE_CHAIN& poly = shape.GetPolyShape().Outline( 0 );
3220
3221 for( int ii = 0; ii < (int) poly.GetPointCount(); ++ii )
3222 poly.SetPoint( ii, scalePt( poly.CPoint( ii ) ) );
3223 }
3224
3225 break;
3226 }
3227
3228 case KICAD_T::SCH_PIN_T:
3229 {
3230 SCH_PIN& pin = static_cast<SCH_PIN&>( item );
3231
3232 pin.SetPosition( scalePt( pin.GetPosition() ) );
3233 pin.SetLength( scaleLen( pin.GetLength() ) );
3234 break;
3235 }
3236
3238 {
3239 SCH_TEXT& txt = static_cast<SCH_TEXT&>( item );
3240
3241 txt.SetPosition( scalePt( txt.GetPosition() ) );
3242 txt.SetTextSize( scaleSize( txt.GetTextSize() ) );
3243 break;
3244 }
3245
3246 default:
3247 break;
3248 }
3249 }
3250
3251 return retval;
3252}
3253
3254
3255void CADSTAR_SCH_ARCHIVE_LOADER::fixUpLibraryPins( LIB_SYMBOL* aSymbolToFix, int aGateNumber )
3256{
3257 auto compLambda =
3258 []( const VECTOR2I& aA, const VECTOR2I& aB )
3259 {
3260 return LexicographicalCompare( aA, aB ) < 0;
3261 };
3262
3263 // Store a list of vertical or horizontal segments in the symbol
3264 // Note: Need the custom comparison function to ensure the map is sorted correctly
3265 std::map<VECTOR2I, SHAPE_LINE_CHAIN, decltype( compLambda )> uniqueSegments( compLambda );
3266
3267 LIB_ITEMS_CONTAINER::ITERATOR shapeIt = aSymbolToFix->GetDrawItems().begin( SCH_SHAPE_T );
3268
3269 for( ; shapeIt != aSymbolToFix->GetDrawItems().end( SCH_SHAPE_T ); ++shapeIt )
3270 {
3271 SCH_SHAPE& shape = static_cast<SCH_SHAPE&>( *shapeIt );
3272
3273 if( aGateNumber > 0 && shape.GetUnit() != aGateNumber )
3274 continue;
3275
3276 if( shape.GetShape() != SHAPE_T::POLY )
3277 continue;
3278
3279 SHAPE_LINE_CHAIN poly = shape.GetPolyShape().Outline( 0 );
3280
3281 if( poly.GetPointCount() == 2 )
3282 {
3283 VECTOR2I pt0 = poly.CPoint( 0 );
3284 VECTOR2I pt1 = poly.CPoint( 1 );
3285
3286 if( pt0 != pt1 && uniqueSegments.count( pt0 ) == 0 && uniqueSegments.count( pt1 ) == 0 )
3287 {
3288 // we are only interested in vertical or horizontal segments
3289 if( pt0.x == pt1.x || pt0.y == pt1.y )
3290 {
3291 uniqueSegments.insert( { pt0, poly } );
3292 uniqueSegments.insert( { pt1, poly } );
3293 }
3294 }
3295 }
3296 }
3297
3298 for( SCH_PIN* pin : aSymbolToFix->GetGraphicalPins( aGateNumber, 0 ) )
3299 {
3300 auto setPinOrientation =
3301 [&]( const EDA_ANGLE& aAngle )
3302 {
3303 EDA_ANGLE angle( aAngle );
3304 angle.Normalize180();
3305
3306 if( angle >= -ANGLE_45 && angle <= ANGLE_45 )
3307 pin->SetOrientation( PIN_ORIENTATION::PIN_RIGHT ); // 0 degrees
3308 else if( angle >= ANGLE_45 && angle <= ANGLE_135 )
3309 pin->SetOrientation( PIN_ORIENTATION::PIN_UP ); // 90 degrees
3310 else if( angle >= ANGLE_135 || angle <= -ANGLE_135 )
3311 pin->SetOrientation( PIN_ORIENTATION::PIN_LEFT ); // 180 degrees
3312 else
3313 pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN ); // -90 degrees
3314 };
3315
3316 if( uniqueSegments.count( pin->GetPosition() ) )
3317 {
3318 SHAPE_LINE_CHAIN& poly = uniqueSegments.at( pin->GetPosition() );
3319
3320 VECTOR2I otherPt = poly.CPoint( 0 );
3321
3322 if( otherPt == pin->GetPosition() )
3323 otherPt = poly.CPoint( 1 );
3324
3325 VECTOR2I vec( otherPt - pin->GetPosition() );
3326
3327 pin->SetLength( vec.EuclideanNorm() );
3328 setPinOrientation( EDA_ANGLE( vec ) );
3329 }
3330 }
3331}
3332
3333
3334std::pair<VECTOR2I, VECTOR2I>
3336{
3337 VECTOR2I upperLeft( Assignments.Settings.DesignLimit.x, 0 );
3338 VECTOR2I lowerRight( 0, Assignments.Settings.DesignLimit.y );
3339
3340 for( const VERTEX& v : aCadstarFigure.Shape.Vertices )
3341 {
3342 if( upperLeft.x > v.End.x )
3343 upperLeft.x = v.End.x;
3344
3345 if( upperLeft.y < v.End.y )
3346 upperLeft.y = v.End.y;
3347
3348 if( lowerRight.x < v.End.x )
3349 lowerRight.x = v.End.x;
3350
3351 if( lowerRight.y > v.End.y )
3352 lowerRight.y = v.End.y;
3353 }
3354
3355 for( CUTOUT cutout : aCadstarFigure.Shape.Cutouts )
3356 {
3357 for( const VERTEX& v : aCadstarFigure.Shape.Vertices )
3358 {
3359 if( upperLeft.x > v.End.x )
3360 upperLeft.x = v.End.x;
3361
3362 if( upperLeft.y < v.End.y )
3363 upperLeft.y = v.End.y;
3364
3365 if( lowerRight.x < v.End.x )
3366 lowerRight.x = v.End.x;
3367
3368 if( lowerRight.y > v.End.y )
3369 lowerRight.y = v.End.y;
3370 }
3371 }
3372
3373 VECTOR2I upperLeftKiCad = getKiCadPoint( upperLeft );
3374 VECTOR2I lowerRightKiCad = getKiCadPoint( lowerRight );
3375
3376 VECTOR2I size = lowerRightKiCad - upperLeftKiCad;
3377
3378 return { upperLeftKiCad, VECTOR2I( abs( size.x ), abs( size.y ) ) };
3379}
3380
3381
3383{
3384 VECTOR2I retval;
3385
3386 retval.x = getKiCadLength( aCadstarPoint.x - m_designCenter.x );
3387 retval.y = -getKiCadLength( aCadstarPoint.y - m_designCenter.y );
3388
3389 return retval;
3390}
3391
3392
3394 const VECTOR2I& aCadstarCentre )
3395{
3396 VECTOR2I retval;
3397
3398 retval.x = getKiCadLength( aCadstarPoint.x - aCadstarCentre.x );
3399 retval.y = -getKiCadLength( aCadstarPoint.y - aCadstarCentre.y );
3400
3401 return retval;
3402}
3403
3404
3406 const VECTOR2I& aMoveVector,
3407 const EDA_ANGLE& aRotation,
3408 const double& aScalingFactor,
3409 const VECTOR2I& aTransformCentre,
3410 const bool& aMirrorInvert )
3411{
3412 VECTOR2I retVal = aPoint;
3413
3414 if( aScalingFactor != 1.0 )
3415 {
3416 //scale point
3417 retVal -= aTransformCentre;
3418 retVal.x = KiROUND( retVal.x * aScalingFactor );
3419 retVal.y = KiROUND( retVal.y * aScalingFactor );
3420 retVal += aTransformCentre;
3421 }
3422
3423 if( aMirrorInvert )
3424 MIRROR( retVal.x, aTransformCentre.x );
3425
3426 if( !aRotation.IsZero() )
3427 RotatePoint( retVal, aTransformCentre, aRotation );
3428
3429 if( aMoveVector != VECTOR2I{ 0, 0 } )
3430 retVal += aMoveVector;
3431
3432 return retVal;
3433}
3434
3435
3437{
3438 return sqrt( ( (double) aPoint.x * (double) aPoint.x )
3439 + ( (double) aPoint.y * (double) aPoint.y ) );
3440}
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.
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.
int getKiCadLength(long long aCadstarLength)
std::map< PART_ID, LIB_SYMBOL * > m_partMap
Cadstar->KiCad Parts.
bool isAttributeVisible(const ATTRIBUTE_ID &aCadstarAttributeID)
VECTOR2I getKiCadPoint(const VECTOR2I &aCadstarPoint)
EDA_ANGLE getAngle(const long long &aCadstarAngle)
std::map< wxString, SYMDEF_ID > m_DefaultSymDefNamesCache
Cache storing symbol names (default alternate) to symdef IDs.
void loadSymbolGateAndPartFields(const SYMDEF_ID &aSymdefID, const PART &aCadstarPart, const GATE_ID &aGateID, LIB_SYMBOL *aSymbol)
void loadFigure(const FIGURE &aCadstarFigure, const LAYER_ID &aCadstarSheetIDOverride, SCH_LAYER_ID aKiCadSchLayerID, const VECTOR2I &aMoveVector={ 0, 0 }, const EDA_ANGLE &aRotation=ANGLE_0, const double &aScalingFactor=1.0, const VECTOR2I &aTransformCentre={ 0, 0 }, const bool &aMirrorInvert=false)
std::map< PART_GATE_ID, SYMDEF_ID > m_partSymbolsMap
Map holding the symbols loaded so far for a particular PART_ID and GATE_ID.
LIB_SYMBOL * getScaledLibPart(const LIB_SYMBOL *aSymbol, long long aScalingFactorNumerator, long long aScalingFactorDenominator)
SYMDEF_ID getSymDefFromName(const wxString &aSymdefName, const wxString &aSymDefAlternate)
std::pair< VECTOR2I, VECTOR2I > getFigureExtentsKiCad(const FIGURE &aCadstarFigure)
std::map< LAYER_ID, SCH_SHEET * > m_sheetMap
Cadstar->KiCad Sheets.
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 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:329
void SetLineStyle(const LINE_STYLE aStyle)
SHAPE_POLY_SET & GetPolyShape()
SHAPE_T GetShape() const
Definition eda_shape.h:175
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:325
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:275
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:514
virtual void SetStart(const VECTOR2I &aStart)
Definition eda_shape.h:279
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:126
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:437
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:408
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:87
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:86
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:386
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:147
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:145
VECTOR2I GetPosition() const override
Definition sch_sheet.h:506
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:73
void SetPosition(const VECTOR2I &aPosition) override
Definition sch_symbol.h:896
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:182
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...
const SHAPE_LINE_CHAIN Reverse() const
Reverse point order in the line chain.
void SetPoint(int aIndex, const VECTOR2I &aPos)
Move a point to a specific location.
int FindSegment(const VECTOR2I &aP, int aThreshold=1) const
Search for segment containing point aP.
int Intersect(const SEG &aSeg, INTERSECTIONS &aIp) const
Find all intersection points between our line chain and the segment aSeg.
void Replace(int aStartIndex, int aEndIndex, const VECTOR2I &aP)
Replace points with indices in range [start_index, end_index] with a single point aP.
virtual size_t GetPointCount() const override
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
const VECTOR2I NearestPoint(const VECTOR2I &aP, bool aAllowInternalShapePoints=true) const
Find a point on the line chain that is closest to point aP.
std::vector< INTERSECTION > INTERSECTIONS
const std::vector< VECTOR2I > & CPoints() const
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:471
@ LAYER_DEVICE
Definition layer_ids.h:488
@ LAYER_WIRE
Definition layer_ids.h:474
@ LAYER_NOTES
Definition layer_ids.h:489
@ LAYER_BUS
Definition layer_ids.h:475
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
@ VERTEX
An indexed rectangle corner or polygon outline vertex; pairs with CONSTRAINT_MEMBER::m_index.
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, default to equal height (1:1 aspect ra...
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:166
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.